namespace ts {
    const enum SignatureFlags {
        None = 0,
        Yield = 1 << 0,
        Await = 1 << 1,
        Type = 1 << 2,
        IgnoreMissingOpenBrace = 1 << 4,
        JSDoc = 1 << 5,
    }

    let NodeConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
    let TokenConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
    let IdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
    let SourceFileConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;

    export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node {
        if (kind === SyntaxKind.SourceFile) {
            return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, pos, end);
        }
        else if (kind === SyntaxKind.Identifier) {
            return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, pos, end);
        }
        else if (!isNodeKind(kind)) {
            return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, pos, end);
        }
        else {
            return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, pos, end);
        }
    }

    function visitNode<T>(cbNode: (node: Node) => T, node: Node | undefined): T | undefined {
        return node && cbNode(node);
    }

    function visitNodes<T>(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray<Node>) => T | undefined) | undefined, nodes: NodeArray<Node> | undefined): T | undefined {
        if (nodes) {
            if (cbNodes) {
                return cbNodes(nodes);
            }
            for (const node of nodes) {
                const result = cbNode(node);
                if (result) {
                    return result;
                }
            }
        }
    }

    /*@internal*/
    export function isJSDocLikeText(text: string, start: number) {
        return text.charCodeAt(start + 1) === Charas.asterisk &&
            text.charCodeAt(start + 2) === Charas.asterisk &&
            text.charCodeAt(start + 3) !== Charas.slash;
    }

    /*@internal*/
    export function 是转换词典类的文本(text: string, start: number) {
        return text.charCodeAt(start + 1) === Charas.slash &&
            (text.charCodeAt(start + 2) === Charas.at || text.charCodeAt(start + 2) === Charas.hash);
    }

    /**
     * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes
     * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,
     * embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns
     * a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned.
     *
     * @param node a given node to visit its children
     * @param cbNode a callback to be invoked for all child nodes
     * @param cbNodes a callback to be invoked for embedded array
     *
     * @remarks `forEachChild` must visit the children of a node in the order
     * that they appear in the source code. The language service depends on this property to locate nodes by position.
     */
    export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
        if (!node || node.kind <= SyntaxKind.LastToken) {
            return;
        }
        switch (node.kind) {
            case SyntaxKind.QualifiedName:
                return visitNode(cbNode, (<QualifiedName>node).left) ||
                    visitNode(cbNode, (<QualifiedName>node).right);
            case SyntaxKind.TypeParameter:
                return visitNode(cbNode, (<TypeParameterDeclaration>node).name) ||
                    visitNode(cbNode, (<TypeParameterDeclaration>node).constraint) ||
                    visitNode(cbNode, (<TypeParameterDeclaration>node).default) ||
                    visitNode(cbNode, (<TypeParameterDeclaration>node).expression);
            case SyntaxKind.ShorthandPropertyAssignment:
                return visitNode(cbNode, (<ShorthandPropertyAssignment>node).name) ||
                    visitNode(cbNode, (<ShorthandPropertyAssignment>node).questionToken) ||
                    visitNode(cbNode, (<ShorthandPropertyAssignment>node).exclamationToken) ||
                    visitNode(cbNode, (<ShorthandPropertyAssignment>node).equalsToken) ||
                    visitNode(cbNode, (<ShorthandPropertyAssignment>node).objectAssignmentInitializer);
            case SyntaxKind.SpreadAssignment:
                return visitNode(cbNode, (<SpreadAssignment>node).expression);
            case SyntaxKind.Parameter:
                return visitNodes(cbNode, cbNodes, (<MethodDeclaration>node).修饰符) ||
                    visitNode(cbNode, (<ParameterDeclaration>node).name) ||
                    visitNode(cbNode, (<ParameterDeclaration>node).questionToken) ||
                    visitNode(cbNode, (<ParameterDeclaration>node).type) ||
                    visitNode(cbNode, (<ParameterDeclaration>node).initializer);
            case SyntaxKind.PropertyDeclaration:
                return visitNode(cbNode, (<PropertyDeclaration>node).name) ||
                    visitNode(cbNode, (<PropertyDeclaration>node).questionToken) ||
                    visitNode(cbNode, (<PropertyDeclaration>node).exclamationToken) ||
                    visitNode(cbNode, (<PropertyDeclaration>node).type) ||
                    visitNode(cbNode, (<PropertyDeclaration>node).initializer);
            case SyntaxKind.PropertySignature:
                return visitNode(cbNode, (<PropertySignature>node).name) ||
                    visitNode(cbNode, (<PropertySignature>node).questionToken) ||
                    visitNode(cbNode, (<PropertySignature>node).type) ||
                    visitNode(cbNode, (<PropertySignature>node).initializer);
            case SyntaxKind.PropertyAssignment:
                return visitNode(cbNode, (<PropertyAssignment>node).name) ||
                    visitNode(cbNode, (<PropertyAssignment>node).questionToken) ||
                    visitNode(cbNode, (<PropertyAssignment>node).initializer);
            case SyntaxKind.VariableDeclaration:
                return visitNode(cbNode, (<VariableDeclaration>node).name) ||
                    visitNode(cbNode, (<VariableDeclaration>node).exclamationToken) ||
                    visitNode(cbNode, (<VariableDeclaration>node).type) ||
                    visitNode(cbNode, (<VariableDeclaration>node).initializer);
            case SyntaxKind.FunctionType:
                return visitNodes(cbNode, cbNodes, (<SignatureDeclaration>node).typeParameters) ||
                    visitNodes(cbNode, cbNodes, (<SignatureDeclaration>node).parameters) ||
                    visitNode(cbNode, (<SignatureDeclaration>node).type);
            case SyntaxKind.内部方法声明_:
                return visitNode(cbNode, (<MethodDeclaration>node).name) ||
                    visitNode(cbNode, (<MethodDeclaration>node).questionToken) ||
                    visitNode(cbNode, (<MethodDeclaration>node).exclamationToken) ||
                    visitNodes(cbNode, cbNodes, (<MethodDeclaration>node).typeParameters) ||
                    visitNodes(cbNode, cbNodes, (<MethodDeclaration>node).parameters) ||
                    visitNode(cbNode, (<MethodDeclaration>node).type) ||
                    visitNode(cbNode, (<MethodDeclaration>node).body);
            case SyntaxKind.MethodDeclaration:
                return visitNode(cbNode, (<MethodDeclaration>node).接受者) ||
                    visitNode(cbNode, (<MethodDeclaration>node).name) ||
                    visitNode(cbNode, (<MethodDeclaration>node).questionToken) ||
                    visitNode(cbNode, (<MethodDeclaration>node).exclamationToken) ||
                    visitNodes(cbNode, cbNodes, (<MethodDeclaration>node).typeParameters) ||
                    visitNodes(cbNode, cbNodes, (<MethodDeclaration>node).parameters) ||
                    visitNode(cbNode, (<MethodDeclaration>node).type) ||
                    visitNode(cbNode, (<MethodDeclaration>node).body);
            case SyntaxKind.MethodSignature:
            case SyntaxKind.FunctionExpression:
            case SyntaxKind.FunctionDeclaration:
            case SyntaxKind.ConstructSignature:
            case SyntaxKind.ConstructDeclaration:
            case SyntaxKind.释放声明_:
            case SyntaxKind.ArrowFunction:
                return visitNode(cbNode, (<FunctionLikeDeclaration>node).name) ||
                    visitNode(cbNode, (<FunctionLikeDeclaration>node).questionToken) ||
                    visitNode(cbNode, (<FunctionLikeDeclaration>node).exclamationToken) ||
                    visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).typeParameters) ||
                    visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).parameters) ||
                    visitNode(cbNode, (<FunctionLikeDeclaration>node).type) ||
                    visitNode(cbNode, (<ArrowFunction>node).equalsGreaterThanToken) ||
                    visitNode(cbNode, (<FunctionLikeDeclaration>node).body);
            case SyntaxKind.区间类型节点_:
                return visitNode(cbNode, (<区间类型节点_>node).开始) ||
                    visitNode(cbNode, (<区间类型节点_>node).结束);
            case SyntaxKind.静态二元表达式类型节点_:
                return visitNode(cbNode, (<静态二元表达式类型节点_>node).left) ||
                    visitNode(cbNode, (<静态二元表达式类型节点_>node).operatorToken) ||
                    visitNode(cbNode, (<静态二元表达式类型节点_>node).right);
            case SyntaxKind.指针类型_:
            case SyntaxKind.动态数组_:
            case SyntaxKind.变长参数_:
                return visitNode(cbNode, (<指针类型节点_>node).type);
            case SyntaxKind.类型限定类型_:
                return visitNode(cbNode, (<类型限定符类型节点_>node).限定符) ||
                    visitNode(cbNode, (<类型限定符类型节点_>node).type);
            case SyntaxKind.词典类型_:
                return visitNode(cbNode, (<词典类型节点_>node).键类型) ||
                    visitNode(cbNode, (<词典类型节点_>node).值类型);
            case SyntaxKind.TypeReference:
                return visitNode(cbNode, (<TypeReferenceNode>node).typeName) ||
                    visitNodes(cbNode, cbNodes, (<TypeReferenceNode>node).typeArguments);
            case SyntaxKind.TypeLiteral:
                return visitNodes(cbNode, cbNodes, (<TypeLiteralNode>node).members);
            case SyntaxKind.ArrayType:
                return visitNode(cbNode, (<ArrayTypeNode>node).elementType) ||
                    visitNode(cbNode, (<ArrayTypeNode>node).长度);
            case SyntaxKind.UnionType:
            case SyntaxKind.IntersectionType:
                return visitNodes(cbNode, cbNodes, (<UnionOrIntersectionTypeNode>node).types);
            case SyntaxKind.ParenthesizedType:
                return visitNode(cbNode, (<ParenthesizedTypeNode>node).type);
            case SyntaxKind.LiteralType:
                return visitNode(cbNode, (<LiteralTypeNode>node).literal);
            case SyntaxKind.词典键值表达式_:
                return visitNode(cbNode, (<词典键值表达式_>node).键表达式) ||
                    visitNode(cbNode, (<词典键值表达式_>node).值表达式);
            case SyntaxKind.截取表达式_:
                return visitNode(cbNode, (<截取表达式_>node).expression) ||
                    visitNode(cbNode, (<截取表达式_>node).开始) ||
                    visitNode(cbNode, (<截取表达式_>node).结束);
            case SyntaxKind.ArrayLiteralExpression:
            case SyntaxKind.动态数组表达式_:
            case SyntaxKind.词典字面量表达式_:
                return visitNode(cbNode, (<动态数组表达式_ | 词典字面量表达式_ | ArrayLiteralExpression>node).type) ||
                    visitNodes(cbNode, cbNodes, (<动态数组表达式_ | 词典字面量表达式_ | ArrayLiteralExpression>node).elements);
            case SyntaxKind.ObjectLiteralExpression:
                return visitNode(cbNode, (<ObjectLiteralExpression>node).type) ||
                    visitNodes(cbNode, cbNodes, (<ObjectLiteralExpression>node).properties);
            case SyntaxKind.PropertyAccessExpression:
                return visitNode(cbNode, (<PropertyAccessExpression>node).expression) ||
                    visitNode(cbNode, (<PropertyAccessExpression>node).questionDotToken) ||
                    visitNode(cbNode, (<PropertyAccessExpression>node).name);
            case SyntaxKind.ElementAccessExpression:
                return visitNode(cbNode, (<ElementAccessExpression>node).expression) ||
                    visitNode(cbNode, (<ElementAccessExpression>node).questionDotToken) ||
                    visitNode(cbNode, (<ElementAccessExpression>node).argumentExpression);
            case SyntaxKind.NewExpression:
                return visitNode(cbNode, (<NewExpression>node).type)||
                    visitNodes(cbNode, cbNodes, (<NewExpression>node).initExpression);
            case SyntaxKind.CallExpression:
                return visitNode(cbNode, (<CallExpression>node).expression) ||
                    visitNode(cbNode, (<CallExpression>node).questionDotToken) ||
                    visitNodes(cbNode, cbNodes, (<CallExpression>node).typeArguments) ||
                    visitNodes(cbNode, cbNodes, (<CallExpression>node).arguments);
            case SyntaxKind.TypeAssertionExpression:
                return visitNode(cbNode, (<TypeAssertionExpression>node).expression) ||
                    visitNode(cbNode, (<TypeAssertionExpression>node).type);
            case SyntaxKind.类型查询表达式_:
            case SyntaxKind.类型转换表达式_:
                return visitNode(cbNode, (<类型转换表达式_ | 类型查询表达式_ | TypeAssertionExpression>node).type) ||
                    visitNode(cbNode, (<类型转换表达式_ | 类型查询表达式_ | TypeAssertionExpression>node).expression);
            case SyntaxKind.删除语句_:
            case SyntaxKind.延迟语句_:
                return visitNode(cbNode, (<删除语句_ | 延迟语句_>node).expression);
            case SyntaxKind.指令语句_:
                return visitNode(cbNode, (<指令语句_>node).参数);
            case SyntaxKind.同步语句_:
                return visitNodes(cbNode, cbNodes, (<| 同步语句_>node).arguments) ||
                    visitNodes(cbNode, cbNodes, (<| 同步语句_>node).statements);
            case SyntaxKind.测试单元语句_:
                return visitNodes(cbNode, cbNodes, (<测试单元语句_>node).statements);
            case SyntaxKind.断言语句_:
                return visitNodes(cbNode, cbNodes, (<断言语句_>node).arguments);
            case SyntaxKind.ParenthesizedExpression:
                return visitNode(cbNode, (<ParenthesizedExpression>node).expression);
            case SyntaxKind.PrefixUnaryExpression:
                return visitNode(cbNode, (<PrefixUnaryExpression>node).operand);
            case SyntaxKind.PostfixUnaryExpression:
                return visitNode(cbNode, (<PostfixUnaryExpression>node).operand);
            case SyntaxKind.BinaryExpression:
                return visitNode(cbNode, (<BinaryExpression>node).left) ||
                    visitNode(cbNode, (<BinaryExpression>node).operatorToken) ||
                    visitNode(cbNode, (<BinaryExpression>node).right);
            case SyntaxKind.NonNullExpression:
                return visitNode(cbNode, (<NonNullExpression>node).expression);
            case SyntaxKind.ConditionalExpression:
                return visitNode(cbNode, (<ConditionalExpression>node).condition) ||
                    visitNode(cbNode, (<ConditionalExpression>node).questionToken) ||
                    visitNode(cbNode, (<ConditionalExpression>node).whenTrue) ||
                    visitNode(cbNode, (<ConditionalExpression>node).colonToken) ||
                    visitNode(cbNode, (<ConditionalExpression>node).whenFalse);
            case SyntaxKind.SpreadElement:
                return visitNode(cbNode, (<SpreadElement>node).expression);
            case SyntaxKind.导入成员块_:
            case SyntaxKind.导入从成员块_:
            case SyntaxKind.Block:
                return visitNodes(cbNode, cbNodes, (<Block | 导入成员块_ | 导入从成员块_ >node).statements);
            case SyntaxKind.SourceFile:
                return visitNodes(cbNode, cbNodes, (<SourceFile>node).statements) ||
                    visitNode(cbNode, (<SourceFile>node).endOfFileToken);
            case SyntaxKind.程序声明_:
                return visitNode(cbNode, (<程序声明_>node).name) ||
                    visitNodes(cbNode, cbNodes, (<程序声明_>node).statements);
            case SyntaxKind.简洁变量语句_:
                return visitNodes(cbNode, cbNodes, (<简洁变量语句_>node).declarations) ||
                    visitNodes(cbNode, cbNodes, (<简洁变量语句_>node).initializers);
            case SyntaxKind.VariableStatement:
                return visitNode(cbNode, (<VariableStatement>node).declarationList);
            case SyntaxKind.VariableDeclarationList:
                return visitNodes(cbNode, cbNodes, (<VariableDeclarationList>node).declarations);
            case SyntaxKind.ExpressionStatement:
                return visitNode(cbNode, (<ExpressionStatement>node).expression);
            case SyntaxKind.IfStatement:
                return visitNode(cbNode, (<IfStatement>node).expression) ||
                    visitNode(cbNode, (<IfStatement>node).thenStatement) ||
                    visitNode(cbNode, (<IfStatement>node).elseStatement);
            case SyntaxKind.导入版本成员_:                
            case SyntaxKind.导入从版本成员_:
            case SyntaxKind.版本语句_:
                return visitNode(cbNode, (<版本语句_ | 导入版本成员_ | 导入从版本成员_>node).expression) ||
                    visitNode(cbNode, (<版本语句_ | 导入版本成员_ | 导入从版本成员_>node).thenStatement) ||
                    visitNode(cbNode, (<版本语句_ | 导入版本成员_ | 导入从版本成员_>node).elseStatement);
            case SyntaxKind.版本表达式语句_:
                return visitNode(cbNode, (<版本表达式语句_>node).expression);
            case SyntaxKind.转换词典语句_:
                return visitNode(cbNode, (<转换词典语句_>node).标识) ||
                    visitNodes(cbNode, cbNodes, (<转换词典语句_>node).elements);
            case SyntaxKind.转换词典表达式_:
                return visitNode(cbNode, (<转换词典表达式_>node).键) ||
                    visitNode(cbNode, (<转换词典表达式_>node).值);
            case SyntaxKind.WhileStatement:
                return visitNode(cbNode, (<WhileStatement>node).expression) ||
                    visitNode(cbNode, (<WhileStatement>node).statement);
            case SyntaxKind.ForStatement:
                return visitNode(cbNode, (<ForStatement>node).initializer) ||
                    visitNode(cbNode, (<ForStatement>node).condition) ||
                    visitNode(cbNode, (<ForStatement>node).incrementor) ||
                    visitNode(cbNode, (<ForStatement>node).statement);
            case SyntaxKind.ForOfStatement:
                return visitNode(cbNode, (<ForOfStatement>node).initializer) ||
                    visitNode(cbNode, (<ForOfStatement>node).expression) ||
                    visitNode(cbNode, (<ForOfStatement>node).statement);
            case SyntaxKind.ContinueStatement:
            case SyntaxKind.BreakStatement:
                return visitNode(cbNode, (<BreakOrContinueStatement>node).label);
            case SyntaxKind.ReturnStatement:
                return visitNode(cbNode, (<ReturnStatement>node).expression);
            case SyntaxKind.SwitchStatement:
                return visitNode(cbNode, (<SwitchStatement>node).expression) ||
                    visitNode(cbNode, (<SwitchStatement>node).caseBlock);
            case SyntaxKind.CaseBlock:
                return visitNodes(cbNode, cbNodes, (<CaseBlock>node).clauses);
            case SyntaxKind.CaseClause:
                return visitNode(cbNode, (<CaseClause>node).expression) ||
                    visitNodes(cbNode, cbNodes, (<CaseClause>node).statements);
            case SyntaxKind.DefaultClause:
                return visitNodes(cbNode, cbNodes, (<DefaultClause>node).statements);
            case SyntaxKind.LabeledStatement:
                return visitNode(cbNode, (<LabeledStatement>node).label) ||
                    visitNode(cbNode, (<LabeledStatement>node).statement);
            case SyntaxKind.ThrowStatement:
                return visitNode(cbNode, (<ThrowStatement>node).expression);
            case SyntaxKind.TryStatement:
                return visitNode(cbNode, (<TryStatement>node).tryBlock) ||
                    visitNode(cbNode, (<TryStatement>node).catchClause) ||
                    visitNode(cbNode, (<TryStatement>node).finallyBlock);
            case SyntaxKind.CatchClause:
                return visitNode(cbNode, (<CatchClause>node).variableDeclaration) ||
                    visitNode(cbNode, (<CatchClause>node).block);

            case SyntaxKind.对象声明_:
                return visitNode(cbNode, (<对象声明_>node).name) ||
                    visitNodes(cbNode, cbNodes, (<对象声明_>node).typeParameters) ||
                    visitNodes(cbNode, cbNodes, (<对象声明_>node).heritageClauses) ||
                    visitNodes(cbNode, cbNodes, (<对象声明_>node).members);

            case SyntaxKind.结构声明_:
                return visitNode(cbNode, (<结构声明_>node).name) ||
                    visitNodes(cbNode, cbNodes, (<结构声明_>node).typeParameters) ||
                    visitNodes(cbNode, cbNodes, (<结构声明_>node).members);

            case SyntaxKind.InterfaceDeclaration:
                return visitNode(cbNode, (<InterfaceDeclaration>node).name) ||
                    visitNodes(cbNode, cbNodes, (<InterfaceDeclaration>node).typeParameters) ||
                    visitNodes(cbNode, cbNodes, (<InterfaceDeclaration>node).heritageClauses) ||
                    visitNodes(cbNode, cbNodes, (<InterfaceDeclaration>node).members);
            case SyntaxKind.别名声明_:
                return visitNode(cbNode, (<别名声明节点_>node).name) ||
                    visitNodes(cbNode, cbNodes, (<别名声明节点_>node).typeParameters) ||
                    visitNode(cbNode, (<别名声明节点_>node).type);
            case SyntaxKind.类型声明_:
                return visitNode(cbNode, (<类型声明节点_>node).name) ||
                    visitNodes(cbNode, cbNodes, (<类型声明节点_>node).typeParameters) ||
                    visitNode(cbNode, (<类型声明节点_>node).type) ||
                    visitNodes(cbNode, cbNodes, (<类型声明节点_>node).members);
            case SyntaxKind.EnumDeclaration:
                return visitNode(cbNode, (<EnumDeclaration>node).name) ||
                    visitNodes(cbNode, cbNodes, (<EnumDeclaration>node).members);
            case SyntaxKind.EnumMember:
                return visitNode(cbNode, (<EnumMember>node).name) ||
                    visitNode(cbNode, (<EnumMember>node).initializer);
            case SyntaxKind.TemplateExpression:
                return visitNode(cbNode, (<TemplateExpression>node).head) || visitNodes(cbNode, cbNodes, (<TemplateExpression>node).templateSpans);
            case SyntaxKind.TemplateSpan:
                return visitNode(cbNode, (<TemplateSpan>node).expression) || visitNode(cbNode, (<TemplateSpan>node).literal);
            case SyntaxKind.HeritageClause:
                return visitNodes(cbNode, cbNodes, (<HeritageClause>node).types);
            case SyntaxKind.ExpressionWithTypeArguments:
                return visitNode(cbNode, (<ExpressionWithTypeArguments>node).expression) ||
                    visitNodes(cbNode, cbNodes, (<ExpressionWithTypeArguments>node).typeArguments);
            case SyntaxKind.CommaListExpression:
                return visitNodes(cbNode, cbNodes, (<CommaListExpression>node).elements);
            case SyntaxKind.导入成员_:
                return visitNode(cbNode, (<导入成员_>node).别名) ||
                    visitNode(cbNode, (<导入成员_>node).模块名);
            case SyntaxKind.导入从成员_:
                return visitNode(cbNode, (<导入从成员_>node).name) ||
                    visitNode(cbNode, (<导入从成员_>node).别名);
            case SyntaxKind.导入声明_:
                return visitNodes(cbNode, cbNodes, (<导入声明_>node).导入组);
            case SyntaxKind.导入从声明_:
                return visitNode(cbNode, (<导入从声明_>node).模块名) ||
                    visitNodes(cbNode, cbNodes, (<导入从声明_>node).导入组);
            case SyntaxKind.OptionalType:
            case SyntaxKind.JSDocTypeExpression:
            case SyntaxKind.JSDocNonNullableType:
            case SyntaxKind.JSDocNullableType:
            case SyntaxKind.JSDocOptionalType:
            case SyntaxKind.JSDocVariadicType:
                return visitNode(cbNode, (<OptionalTypeNode | JSDocTypeExpression | JSDocTypeReferencingNode>node).type);
            case SyntaxKind.JSDocFunctionType:
                return visitNodes(cbNode, cbNodes, (<JSDocFunctionType>node).parameters) ||
                    visitNode(cbNode, (<JSDocFunctionType>node).type);
            case SyntaxKind.JSDocComment:
                return visitNodes(cbNode, cbNodes, (<JSDoc>node).tags);
            case SyntaxKind.JSDocParameterTag:
            case SyntaxKind.JSDocPropertyTag:
                return visitNode(cbNode, (node as JSDocTag).tagName) ||
                    ((node as JSDocPropertyLikeTag).isNameFirst
                        ? visitNode(cbNode, (<JSDocPropertyLikeTag>node).name) ||
                        visitNode(cbNode, (<JSDocPropertyLikeTag>node).typeExpression)
                        : visitNode(cbNode, (<JSDocPropertyLikeTag>node).typeExpression) ||
                        visitNode(cbNode, (<JSDocPropertyLikeTag>node).name));
            case SyntaxKind.JSDocAuthorTag:
                return visitNode(cbNode, (node as JSDocTag).tagName);
            case SyntaxKind.JSDocAugmentsTag:
                return visitNode(cbNode, (node as JSDocTag).tagName) ||
                    visitNode(cbNode, (<JSDocAugmentsTag>node).class);
            case SyntaxKind.JSDocTemplateTag:
                return visitNode(cbNode, (node as JSDocTag).tagName) ||
                    visitNode(cbNode, (<JSDocTemplateTag>node).constraint) ||
                    visitNodes(cbNode, cbNodes, (<JSDocTemplateTag>node).typeParameters);
            case SyntaxKind.JSDocTypedefTag:
                return visitNode(cbNode, (node as JSDocTag).tagName) ||
                    ((node as JSDocTypedefTag).typeExpression &&
                        (node as JSDocTypedefTag).typeExpression!.kind === SyntaxKind.JSDocTypeExpression
                        ? visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression) ||
                        visitNode(cbNode, (<JSDocTypedefTag>node).fullName)
                        : visitNode(cbNode, (<JSDocTypedefTag>node).fullName) ||
                        visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression));
            case SyntaxKind.JSDocCallbackTag:
                return visitNode(cbNode, (node as JSDocTag).tagName) ||
                    visitNode(cbNode, (node as JSDocCallbackTag).fullName) ||
                    visitNode(cbNode, (node as JSDocCallbackTag).typeExpression);
            case SyntaxKind.JSDocReturnTag:
            case SyntaxKind.JSDocTypeTag:
            case SyntaxKind.JSDocThisTag:
            case SyntaxKind.JSDocEnumTag:
                return visitNode(cbNode, (node as JSDocTag).tagName) ||
                    visitNode(cbNode, (node as JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag).typeExpression);
            case SyntaxKind.JSDocSignature:
                return forEach((<JSDocSignature>node).typeParameters, cbNode) ||
                    forEach((<JSDocSignature>node).parameters, cbNode) ||
                    visitNode(cbNode, (<JSDocSignature>node).type);
            case SyntaxKind.JSDocTypeLiteral:
                return forEach((node as JSDocTypeLiteral).jsDocPropertyTags, cbNode);
            case SyntaxKind.JSDocTag:
                return visitNode(cbNode, (node as JSDocTag).tagName);
            case SyntaxKind.PartiallyEmittedExpression:
                return visitNode(cbNode, (<PartiallyEmittedExpression>node).expression);
        }
    }

    export function createSourceFile(fileName: string, sourceText: string, setParentNodes = false): SourceFile {
        performance.mark("beforeParse");
        let result: SourceFile;

        perfLogger.logStartParseSourceFile(fileName);
        const 是JSON = isJsonFileName(fileName)
        if (是JSON) {
            result = Parser.parseSourceFile(fileName, sourceText, /*syntaxCursor*/ undefined, setParentNodes);
        }
        else {
            result = Parser.parseSourceFile(fileName, sourceText, /*syntaxCursor*/ undefined, setParentNodes);
        }
        perfLogger.logStopParseSourceFile();

        performance.mark("afterParse");
        performance.measure("Parse", "beforeParse", "afterParse");
        return result;
    }

    export function parseIsolatedEntityName(text: string): EntityName | undefined {
        return Parser.parseIsolatedEntityName(text);
    }

    /**
     * Parse json text into SyntaxTree and return node and parse errors if any
     * @param fileName
     * @param sourceText
     */
    export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile {
        return Parser.parseJsonText(fileName, sourceText);
    }

    // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter
    // indicates what changed between the 'text' that this SourceFile has and the 'newText'.
    // The SourceFile will be created with the compiler attempting to reuse as many nodes from
    // this file as possible.
    //
    // Note: this function mutates nodes from this SourceFile. That means any existing nodes
    // from this SourceFile that are being held onto may change as a result (including
    // becoming detached from any SourceFile).  It is recommended that this SourceFile not
    // be used once 'update' is called on it.
    export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks = false): SourceFile {
        const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks);
        // Because new source file node is created, it may not have the flag PossiblyContainDynamicImport. This is the case if there is no new edit to add dynamic import.
        // We will manually port the flag to the new source file.
        newSourceFile.flags |= sourceFile.flags;
        return newSourceFile;
    }

    /* @internal */
    export function parseIsolatedJSDocComment(content: string, start?: number, length?: number) {
        const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length);
        if (result && result.jsDoc) {
            // because the jsDocComment was parsed out of the source file, it might
            // not be covered by the fixupParentReferences.
            Parser.fixupParentReferences(result.jsDoc);
        }

        return result;
    }

    export function 是内置版本或内置版本子版本(vs: string) {
        if (dlang_VersionIdentifier.has(vs) && dlang_关键字.has(vs)) {
            return true;
        }
        return forEach(dlang_vs, vv => startsWith(vv, vs + "_"));
    }

    export let 文件内使用的版本标识符组: Set<string> = new Set(["D_LP64" , "unittest"]);

    // Implement the parser as a singleton module.  We do this for perf reasons because creating
    // parser instances can actually be expensive enough to impact us on projects with many source
    // files.
    namespace Parser {
        // Share a single scanner across all calls to parse a source file.  This helps speed things
        // up by avoiding the cost of creating/compiling scanners over and over again.
        const scanner = createScanner(/*skipTrivia*/ true);

        // capture constructors in 'initializeState' to avoid null checks
        let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
        let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
        let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
        let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;

        let sourceFile: SourceFile;
        let parseDiagnostics: DiagnosticWithLocation[];
        let syntaxCursor: IncrementalParser.SyntaxCursor | undefined;
        let currentToken: SyntaxKind;
        let 正在编译全局变量 = false;
        let sourceText: string;
        let nodeCount: number;
        let identifiers: Map<string>;
        let identifierCount: number;

        let parsingContext: ParsingContext;

        let notParenthesizedArrow: Map<true> | undefined;
        let 外部方法收集器: MethodDeclaration[];

        // Flags that dictate what parsing context we're in.  For example:
        // Whether or not we are in strict parsing mode.  All that changes in strict parsing mode is
        // that some tokens that would be considered identifiers may be considered keywords.
        //
        // When adding more parser context flags, consider which is the more common case that the
        // flag will be in.  This should be the 'false' state for that flag.  The reason for this is
        // that we don't store data in our nodes unless the value is in the *non-default* state.  So,
        // for example, more often than code 'allows-in' (or doesn't 'disallow-in').  We opt for
        // 'disallow-in' set to 'false'.  Otherwise, if we had 'allowsIn' set to 'true', then almost
        // all nodes would need extra state on them to store this info.
        //
        // Note: 'allowIn' and 'allowYield' track 1:1 with the [in] and [yield] concepts in the ES6
        // grammar specification.
        //
        // An important thing about these context concepts.  By default they are effectively inherited
        // while parsing through every grammar production.  i.e. if you don't change them, then when
        // you parse a sub-production, it will have the same context values as the parent production.
        // This is great most of the time.  After all, consider all the 'expression' grammar productions
        // and how nearly all of them pass along the 'in' and 'yield' context values:
        //
        // EqualityExpression[In, Yield] :
        //      RelationalExpression[?In, ?Yield]
        //      EqualityExpression[?In, ?Yield] == RelationalExpression[?In, ?Yield]
        //      EqualityExpression[?In, ?Yield] != RelationalExpression[?In, ?Yield]
        //      EqualityExpression[?In, ?Yield] === RelationalExpression[?In, ?Yield]
        //      EqualityExpression[?In, ?Yield] !== RelationalExpression[?In, ?Yield]
        //
        // Where you have to be careful is then understanding what the points are in the grammar
        // where the values are *not* passed along.  For example:
        //
        // SingleNameBinding[Yield,GeneratorParameter]
        //      [+GeneratorParameter]BindingIdentifier[Yield] Initializer[In]opt
        //      [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt
        //
        // Here this is saying that if the GeneratorParameter context flag is set, that we should
        // explicitly set the 'yield' context flag to false before calling into the BindingIdentifier
        // and we should explicitly unset the 'yield' context flag before calling into the Initializer.
        // production.  Conversely, if the GeneratorParameter context flag is not set, then we
        // should leave the 'yield' context flag alone.
        //
        // Getting this all correct is tricky and requires careful reading of the grammar to
        // understand when these values should be changed versus when they should be inherited.
        //
        // Note: it should not be necessary to save/restore these flags during speculative/lookahead
        // parsing.  These context flags are naturally stored and restored through normal recursive
        // descent parsing and unwinding.
        let contextFlags: NodeFlags;
        let 禁止返回表达式 = false;
        let 允许基类调用 = false;
        let 允许类型计算 = false;
        let 是版本另如容器块 = false;

        // Whether or not we've had a parse error since creating the last AST node.  If we have
        // encountered an error, it will be stored on the next AST node we create.  Parse errors
        // can be broken down into three categories:
        //
        // 1) An error that occurred during scanning.  For example, an unterminated literal, or a
        //    character that was completely not understood.
        //
        // 2) A token was expected, but was not present.  This type of error is commonly produced
        //    by the 'parseExpected' function.
        //
        // 3) A token was present that no parsing function was able to consume.  This type of error
        //    only occurs in the 'abortParsingListOrMoveToNextToken' function when the parser
        //    decides to skip the token.
        //
        // In all of these cases, we want to mark the next node as having had an error before it.
        // With this mark, we can know in incremental settings if this node can be reused, or if
        // we have to reparse it.  If we don't keep this information around, we may just reuse the
        // node.  in that event we would then not produce the same errors as we did before, causing
        // significant confusion problems.
        //
        // Note: it is necessary that this value be saved/restored during speculative/lookahead
        // parsing.  During lookahead parsing, we will often create a node.  That node will have
        // this value attached, and then this value will be set back to 'false'.  If we decide to
        // rewind, we must get back to the same value we had prior to the lookahead.
        //
        // Note: any errors at the end of the file that do not precede a regular node, should get
        // attached to the EOF token.
        let parseErrorBeforeNextFinishedNode = false;

        export function parseSourceFile(fileName: string, sourceText: string, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false): SourceFile {
            if (isJsonFileName(fileName)) {
                const result = parseJsonText(fileName, sourceText, syntaxCursor, setParentNodes);
                convertToObjectWorker(result, result.parseDiagnostics, /*returnValue*/ false, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined);
                result.amdDependencies = emptyArray;
                return result;
            }
            initializeState(sourceText, syntaxCursor, undefined);
            const result = parseSourceFileWorker(fileName, setParentNodes);
            clearState();
            return result;
        }

        export function parseIsolatedEntityName(content: string): EntityName | undefined {
            // Choice of `isDeclarationFile` should be arbitrary
            initializeState(content, /*syntaxCursor*/ undefined, undefined); // Htwx  ScriptKind.JS
            // Prime the scanner.
            nextToken();
            const entityName = parseEntityName(/*allowReservedWords*/ true);
            const isInvalid = token() === SyntaxKind.EndOfFileToken && !parseDiagnostics.length;
            clearState();
            return isInvalid ? entityName : undefined;
        }
        
        export function parseJsonText(fileName: string, sourceText: string, syntaxCursor?: IncrementalParser.SyntaxCursor, setParentNodes?: boolean): JsonSourceFile {
            initializeState(sourceText, syntaxCursor, /*是JSON */ true);
            // Set source file so that errors will be reported with this file name
            sourceFile = createSourceFile(fileName, /*isDeclaration*/ false);
            sourceFile.flags = contextFlags;

            // Prime the scanner.
            nextToken();
            const pos = getNodePos();
            if (token() === SyntaxKind.EndOfFileToken) {
                sourceFile.statements = createNodeArray([], pos, pos);
                sourceFile.endOfFileToken = parseTokenNode<EndOfFileToken>();
            }
            else {
                const statement = createNode(SyntaxKind.ExpressionStatement) as JsonObjectExpressionStatement;
                switch (token()) {
                    case SyntaxKind.OpenBracketToken:
                        statement.expression = parseArrayLiteralExpression();
                        break;
                    case SyntaxKind.TrueKeyword:
                    case SyntaxKind.FalseKeyword:
                    case SyntaxKind.NullKeyword:
                        statement.expression = parseTokenNode<BooleanLiteral | NullLiteral>();
                        break;
                    case SyntaxKind.MinusToken:
                        if (lookAhead(() => nextToken() === SyntaxKind.NumericLiteral && nextToken() !== SyntaxKind.ColonToken)) {
                            statement.expression = parsePrefixUnaryExpression() as JsonMinusNumericLiteral;
                        }
                        else {
                            statement.expression = parseObjectLiteralExpression();
                        }
                        break;
                    case SyntaxKind.NumericLiteral:
                    case SyntaxKind.StringLiteral:
                        if (lookAhead(() => nextToken() !== SyntaxKind.ColonToken)) {
                            statement.expression = parseLiteralNode() as StringLiteral | NumericLiteral;
                            break;
                        }
                    // falls through
                    default:
                        statement.expression = parseObjectLiteralExpression();
                        break;
                }
                finishNode(statement);
                sourceFile.statements = createNodeArray([statement], pos);
                sourceFile.endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, Diagnostics.Unexpected_token);
            }

            if (setParentNodes) {
                fixupParentReferences(sourceFile);
            }

            sourceFile.nodeCount = nodeCount;
            sourceFile.identifierCount = identifierCount;
            sourceFile.identifiers = identifiers;
            sourceFile.parseDiagnostics = parseDiagnostics;

            const result = sourceFile as JsonSourceFile;
            clearState();
            return result;
        }

        function initializeState(_sourceText: string, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, 是JSON = false) {
            NodeConstructor = objectAllocator.getNodeConstructor();
            TokenConstructor = objectAllocator.getTokenConstructor();
            IdentifierConstructor = objectAllocator.getIdentifierConstructor();
            SourceFileConstructor = objectAllocator.getSourceFileConstructor();
            sourceText = _sourceText;
            syntaxCursor = _syntaxCursor;
            parseDiagnostics = [];
            parsingContext = 0;
            identifiers = createMap<string>();
            identifierCount = 0;
            nodeCount = 0;
            contextFlags = 是JSON ? NodeFlags.JsonFile : NodeFlags.None;
            parseErrorBeforeNextFinishedNode = false;
            // Initialize and prime the scanner before parsing the source elements.
            scanner.setText(sourceText);
            scanner.setOnError(scanError);
        }

        function clearState() {
            // Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily.
            scanner.setText("");
            scanner.setOnError(undefined);

            // Clear any data.  We don't want to accidentally hold onto it for too long.
            parseDiagnostics = undefined!;
            sourceFile = undefined!;
            identifiers = undefined!;
            syntaxCursor = undefined;
            sourceText = undefined!;
            notParenthesizedArrow = undefined!;
            外部方法收集器 = undefined!;
            正在编译全局变量 = false;
            允许类型计算 = false;
            是版本另如容器块 = false;
        }

        function parseSourceFileWorker(fileName: string, setParentNodes: boolean): SourceFile {
            try {
                const isDeclarationFile = isDeclarationFileName(fileName);
                if (isDeclarationFile) {
                    contextFlags |= NodeFlags.Ambient;
                }
                sourceFile = createSourceFile(fileName, isDeclarationFile);
                sourceFile.flags = contextFlags;

                // Prime the scanner.
                nextToken();

                sourceFile.statements = parseList(ParsingContext.源码顶级语句_, 解析源码顶级语句);
                if (外部方法收集器) sourceFile.外部方法组 = 外部方法收集器;
                if (!syntaxCursor) Debug.assert(token() === SyntaxKind.EndOfFileToken);
                sourceFile.endOfFileToken = addJSDocComment(parseTokenNode());

                sourceFile.nodeCount = nodeCount;
                sourceFile.identifierCount = identifierCount;
                sourceFile.identifiers = identifiers;
                sourceFile.parseDiagnostics = parseDiagnostics;

                if (setParentNodes) {
                    fixupParentReferences(sourceFile);
                }
                return sourceFile;
            }
            catch (e) {
                写日志("+++++++++++++++++++++ 编译错误 +++++++++++++++++++++++++++");
                return sourceFile;
            }
        }

        function 添加转换词典<T extends HasJSDoc>(node: T): T {
            Debug.assert(!node.dict); // Should only be called once per node
            const dict = mapDefined(获取转换词典评论范围(node, sourceFile.text), comment => JSDocParser.编译转换词典(node, comment.pos, comment.end - comment.pos));
            if (dict.length) node.dict = dict;            
            return node;
        }

        function addJSDocComment<T extends HasJSDoc>(node: T): T {
            Debug.assert(!node.jsDoc); // Should only be called once per node
            const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceFile.text), comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos));
            if (jsDoc.length) node.jsDoc = jsDoc;            
            return node;
        }

        export function fixupParentReferences(rootNode: Node) {
            // normally parent references are set during binding. However, for clients that only need
            // a syntax tree, and no semantic features, then the binding process is an unnecessary
            // overhead.  This functions allows us to set all the parents, without all the expense of
            // binding.

            let parent: Node = rootNode;
            forEachChild(rootNode, visitNode);
            return;

            function visitNode(n: Node): void {
                // walk down setting parents that differ from the parent we think it should be.  This
                // allows us to quickly bail out of setting parents for subtrees during incremental
                // parsing
                if (n.parent !== parent) {
                    n.parent = parent;

                    const saveParent = parent;
                    parent = n;
                    forEachChild(n, visitNode);
                    if (hasJSDocNodes(n)) {
                        for (const jsDoc of n.jsDoc!) {
                            jsDoc.parent = n;
                            parent = jsDoc;
                            forEachChild(jsDoc, visitNode);
                        }
                    }
                    if(有转换词典节点(n)){
                        for (const dict of n.dict!) {
                            dict.parent = n;
                            parent = dict;
                            forEachChild(dict, visitNode);
                        }
                    }
                    parent = saveParent;
                }
            }
        }

        function createSourceFile(fileName: string, isDeclarationFile: boolean): SourceFile {
            // code from createNode is inlined here so createNode won't have to deal with special case of creating source files
            // this is quite rare comparing to other nodes and createNode should be as fast as possible
            const sourceFile = <SourceFile>new SourceFileConstructor(SyntaxKind.SourceFile, /*pos*/ 0, /* end */ sourceText.length);
            nodeCount++;

            sourceFile.text = sourceText;
            sourceFile.bindDiagnostics = [];
            sourceFile.bindSuggestionDiagnostics = undefined;
            sourceFile.fileName = normalizePath(fileName);
            sourceFile.isDeclarationFile = isDeclarationFile;

            return sourceFile;
        }

        function setContextFlag(val: boolean, flag: NodeFlags) {
            if (val) {
                contextFlags |= flag;
            }
            else {
                contextFlags &= ~flag;
            }
        }


        function doInsideOfContext<T>(context: NodeFlags, func: () => T): T {
            // contextFlagsToSet will contain only the context flags that
            // are not currently set that we need to temporarily enable.
            // We don't just blindly reset to the previous flags to ensure
            // that we do not mutate cached flags for the incremental
            // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and
            // HasAggregatedChildData).
            const contextFlagsToSet = context & ~contextFlags;
            if (contextFlagsToSet) {
                // set the requested context flags
                setContextFlag(/*val*/ true, contextFlagsToSet);
                const result = func();
                // reset the context flags we just set
                setContextFlag(/*val*/ false, contextFlagsToSet);
                return result;
            }

            // no need to do anything special as we are already in all of the requested contexts
            return func();
        }


        function 做禁止属性签名上下文<T>(func: () => T): T {
            return doInsideOfContext(NodeFlags.禁止属性签名上下文_, func);
        }

        function inContext(flags: NodeFlags) {
            return (contextFlags & flags) !== 0;
        }

        function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): void {
            parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), message, arg0);
        }

        function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): void {
            // Don't report another error if it would just be at the same position as the last error.
            const lastError = lastOrUndefined(parseDiagnostics);
            if (!lastError || start !== lastError.start) {
                parseDiagnostics.push(createFileDiagnostic(sourceFile, start, length, message, arg0));
            }

            // Mark that we've encountered an error.  We'll set an appropriate bit on the next
            // node we finish so that it can't be reused incrementally.
            parseErrorBeforeNextFinishedNode = true;
        }

        function parseErrorAt(start: number, end: number, message: DiagnosticMessage, arg0?: any): void {
            parseErrorAtPosition(start, end - start, message, arg0);
        }

        function scanError(message: DiagnosticMessage, length: number): void {
            parseErrorAtPosition(scanner.getTextPos(), length, message);
        }

        function getNodePos(): number {
            return scanner.getStartPos();
        }

        // Use this function to access the current token instead of reading the currentToken
        // variable. Since function results aren't narrowed in control flow analysis, this ensures
        // that the type checker doesn't make wrong assumptions about the type of the current
        // token (e.g. a call to nextToken() changes the current token but the checker doesn't
        // reason about this side effect).  Mainstream VMs inline simple functions like this, so
        // there is no performance penalty.
        function token(): SyntaxKind {
            return currentToken;
        }

        function nextTokenWithoutCheck() {
            return currentToken = scanner.scan();
        }

        function nextToken(): SyntaxKind {
            // if the keyword had an escape
            if (isKeyword(currentToken) && (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape())) {
                // issue a parse error for the escape
                parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), Diagnostics.Keywords_cannot_contain_escape_characters);
            }
            return nextTokenWithoutCheck();
        }
        
        function 下个词典语句令牌(): 转换词典语句令牌_ {
            return currentToken = scanner.扫描词典语句令牌();
        }

        function nextTokenJSDoc(): JSDocSyntaxKind {
            return currentToken = scanner.scanJsDocToken();
        }

        function reScanGreaterToken(): SyntaxKind {
            return currentToken = scanner.reScanGreaterToken();
        }

        function reScanSlashToken(): SyntaxKind {
            return currentToken = scanner.reScanSlashToken();
        }

        function reScanTemplateToken(): SyntaxKind {
            return currentToken = scanner.reScanTemplateToken();
        }

        function reScanLessThanToken(): SyntaxKind {
            return currentToken = scanner.reScanLessThanToken();
        }

        function speculationHelper<T>(callback: () => T, isLookAhead: boolean): T {
            // Keep track of the state we'll need to rollback to if lookahead fails (or if the
            // caller asked us to always reset our state).
            const saveToken = currentToken;
            const saveParseDiagnosticsLength = parseDiagnostics.length;
            const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode;

            // Note: it is not actually necessary to save/restore the context flags here.  That's
            // because the saving/restoring of these flags happens naturally through the recursive
            // descent nature of our parser.  However, we still store this here just so we can
            // assert that invariant holds.
            const saveContextFlags = contextFlags;

            // If we're only looking ahead, then tell the scanner to only lookahead as well.
            // Otherwise, if we're actually speculatively parsing, then tell the scanner to do the
            // same.
            const result = isLookAhead
                ? scanner.lookAhead(callback)
                : scanner.tryScan(callback);

            Debug.assert(saveContextFlags === contextFlags);

            // If our callback returned something 'falsy' or we're just looking ahead,
            // then unconditionally restore us to where we were.
            if (!result || isLookAhead) {
                currentToken = saveToken;
                parseDiagnostics.length = saveParseDiagnosticsLength;
                parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode;
            }

            return result;
        }

        /** Invokes the provided callback then unconditionally restores the parser to the state it
         * was in immediately prior to invoking the callback.  The result of invoking the callback
         * is returned from this function.
         */
        function lookAhead<T>(callback: () => T): T {
            return speculationHelper(callback, /*isLookAhead*/ true);
        }

        /** Invokes the provided callback.  If the callback returns something falsy, then it restores
         * the parser to the state it was in immediately prior to invoking the callback.  If the
         * callback returns something truthy, then the parser state is not rolled back.  The result
         * of invoking the callback is returned from this function.
         */
        function tryParse<T>(callback: () => T): T {
            return speculationHelper(callback, /*isLookAhead*/ false);
        }

        // Ignore strict mode flag because we will report an error in type checker instead.
        function isIdentifier(): boolean {
            if (token() === SyntaxKind.Identifier) {
                return true;
            }

            return token() > SyntaxKind.LastReservedWord;
        }

        function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldAdvance = true): boolean {
            if (token() === kind) {
                if (shouldAdvance) {
                    nextToken();
                }
                return true;
            }

            // Report specific message if provided with one.  Otherwise, report generic fallback message.
            if (diagnosticMessage) {
                parseErrorAtCurrentToken(diagnosticMessage);
            }
            else {
                parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind));
            }
            return false;
        }

        function 编译必须转换词典令牌(kind: 转换词典语句令牌_) {
            if (token() === kind) {
                下个词典语句令牌();
                return true;
            }
            parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind));
            return false;
        }

        function parseExpectedJSDoc(kind: JSDocSyntaxKind) {
            if (token() === kind) {
                nextTokenJSDoc();
                return true;
            }
            parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind));
            return false;
        }

        function parseOptional(t: SyntaxKind): boolean {
            if (token() === t) {
                nextToken();
                return true;
            }
            return false;
        }

        function parseOptionalToken<TKind extends SyntaxKind>(t: TKind): Token<TKind>;
        function parseOptionalToken(t: SyntaxKind): Node | undefined {
            if (token() === t) {
                return parseTokenNode();
            }
            return undefined;
        }

        function parseOptionalTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>;
        function parseOptionalTokenJSDoc(t: JSDocSyntaxKind): Node | undefined {
            if (token() === t) {
                return parseTokenNodeJSDoc();
            }
            return undefined;
        }

        function parseExpectedToken<TKind extends SyntaxKind>(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Token<TKind>;
        function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Node {
            return parseOptionalToken(t) ||
                createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t));
        }

        function parseExpectedTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>;
        function parseExpectedTokenJSDoc(t: JSDocSyntaxKind): Node {
            return parseOptionalTokenJSDoc(t) ||
                createMissingNode(t, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(t));
        }

        function parseTokenNode<T extends Node>(): T {
            const node = <T>createNode(token());
            nextToken();
            return finishNode(node);
        }

        function parseTokenNodeJSDoc<T extends Node>(): T {
            const node = <T>createNode(token());
            nextTokenJSDoc();
            return finishNode(node);
        }

        function canParseSemicolon() {
            // If there's a real semicolon, then we can always parse it out.
            if (token() === SyntaxKind.SemicolonToken) {
                return true;
            }

            // We can parse out an optional semicolon in ASI cases in the following cases.
            return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak();
        }

        function parseSemicolon(): boolean {
            if (canParseSemicolon()) {
                if (token() === SyntaxKind.SemicolonToken) {
                    // consume the semicolon if it was explicitly provided.
                    nextToken();
                }

                return true;
            }
            else {
                return parseExpected(SyntaxKind.SemicolonToken);
            }
        }

        function 解析分号或逗号(): boolean {
            if (canParseSemicolon()) {
                if (token() === SyntaxKind.SemicolonToken) {
                    // consume the semicolon if it was explicitly provided.
                    nextToken();
                }

                return true;
            }
            else {
                return parseExpected(SyntaxKind.CommaToken);
            }
        }

        function createNode(kind: SyntaxKind, pos?: number): Node {
            nodeCount++;
            const p = pos! >= 0 ? pos! : scanner.getStartPos();
            return isNodeKind(kind) || kind === SyntaxKind.Unknown ? new NodeConstructor(kind, p, p) :
                kind === SyntaxKind.Identifier ? new IdentifierConstructor(kind, p, p) :
                    new TokenConstructor(kind, p, p);
        }

        function createNodeWithJSDoc(kind: SyntaxKind, pos?: number): Node {
            const node = createNode(kind, pos);
            if (scanner.getTokenFlags() & TokenFlags.PrecedingJSDocComment) {
                addJSDocComment(<HasJSDoc>node);
            }
            if (scanner.getTokenFlags() & TokenFlags.编译转换词典_) {
                添加转换词典(<HasJSDoc>node);
            }
            
            return node;
        }

        function createNodeArray<T extends Node>(elements: T[], pos: number, end?: number): NodeArray<T> {
            // Since the element list of a node array is typically created by starting with an empty array and
            // repeatedly calling push(), the list may not have the optimal memory layout. We invoke slice() for
            // small arrays (1 to 4 elements) to give the VM a chance to allocate an optimal representation.
            const length = elements.length;
            const array = <MutableNodeArray<T>>(length >= 1 && length <= 4 ? elements.slice() : elements);
            array.pos = pos;
            array.end = end === undefined ? scanner.getStartPos() : end;
            return array;
        }

        function finishNode<T extends Node>(node: T, end?: number): T {
            node.end = end === undefined ? scanner.getStartPos() : end;

            if (contextFlags) {
                node.flags |= contextFlags;
            }

            // Keep track on the node if we encountered an error while parsing it.  If we did, then
            // we cannot reuse the node incrementally.  Once we've marked this node, clear out the
            // flag so that we don't mark any subsequent nodes.
            if (parseErrorBeforeNextFinishedNode) {
                parseErrorBeforeNextFinishedNode = false;
                node.flags |= NodeFlags.ThisNodeHasError;
            }

            return node;
        }

        function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: false, diagnosticMessage?: DiagnosticMessage, arg0?: any): T;
        function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T;
        function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T {
            if (reportAtCurrentPosition) {
                parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0);
            }
            else if (diagnosticMessage) {
                parseErrorAtCurrentToken(diagnosticMessage, arg0);
            }

            const result = createNode(kind);

            if (kind === SyntaxKind.Identifier) {
                (result as Identifier).escapedText = "" as string;
            }
            else if (isLiteralKind(kind) || isTemplateLiteralKind(kind)) {
                (result as LiteralLikeNode).text = "";
            }

            return finishNode(result) as T;
        }

        function internIdentifier(text: string): string {
            let identifier = identifiers.get(text);
            if (identifier === undefined) {
                identifiers.set(text, identifier = text);
            }
            return identifier;
        }

        // An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues
        // with magic property names like '__proto__'. The 'identifiers' object is used to share a single string instance for
        // each identifier in order to reduce memory consumption.
        function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage): Identifier {
            identifierCount++;
            if (isIdentifier) {
                const node = <Identifier>createNode(SyntaxKind.Identifier);

                // Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker
                if (token() !== SyntaxKind.Identifier) {
                    node.originalKeywordKind = token();
                }
                node.escapedText = internIdentifier(scanner.getTokenValue());
                const 是空标识符 = !!(scanner.getTokenFlags() & TokenFlags.是空标识符_);
                const 是私有的 = !!(scanner.getTokenFlags() & TokenFlags.是私有的_);
                if (是空标识符) {
                    node.是空标识符 = true;
                }
                else if (是私有的) {
                    node.是私有的 = true;
                }
                nextTokenWithoutCheck();
                return finishNode(node);
            }

            // Only for end of file because the error gets reported incorrectly on embedded script tags.
            const reportAtCurrentPosition = token() === SyntaxKind.EndOfFileToken;

            const isReservedWord = scanner.isReservedWord();
            const msgArg = scanner.getTokenText();

            const defaultMessage = isReservedWord ?
                Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here :
                Diagnostics.Identifier_expected;

            return createMissingNode<Identifier>(SyntaxKind.Identifier, reportAtCurrentPosition, diagnosticMessage || defaultMessage, msgArg);
        }

        function parseIdentifier(diagnosticMessage?: DiagnosticMessage): Identifier {
            return createIdentifier(isIdentifier(), diagnosticMessage);
        }

        function parseIdentifierName(diagnosticMessage?: DiagnosticMessage): Identifier {
            return createIdentifier(tokenIsIdentifierOrKeyword(token()), diagnosticMessage);
        }

        function isLiteralPropertyName(): boolean {
            return tokenIsIdentifierOrKeyword(token()) ||
                token() === SyntaxKind.StringLiteral ||
                token() === SyntaxKind.NumericLiteral;
        }

        function parsePropertyNameWorker(): PropertyName {
            if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral) {
                const node = <StringLiteral | NumericLiteral>parseLiteralNode();
                node.text = internIdentifier(node.text);
                return node;
            }
            return parseIdentifierName();
        }

        function parsePropertyName(): PropertyName {
            return parsePropertyNameWorker();
        }

        // True if positioned at the start of a list element
        function isListElement(parsingContext: ParsingContext, inErrorRecovery: boolean): boolean {
            switch (parsingContext) {
                case ParsingContext.源码顶级语句_:
                    return !(token() === SyntaxKind.ColonToken && inErrorRecovery) && (是源码顶级语句开始() || 是程序集顶级语句());
                case ParsingContext.解析导入语句_:
                case ParsingContext.解析导入从语句_:
                    return isIdentifier() || token() === SyntaxKind.StringLiteral || token() === SyntaxKind.版本关键字_;
                case ParsingContext.程序集顶级语句_:
                    return !(token() === SyntaxKind.SemicolonToken && inErrorRecovery) && 是程序集顶级语句();
                case ParsingContext.BlockStatements:
                case ParsingContext.SwitchClauseStatements:
                    // If we're in error recovery, then we don't want to treat ';' as an empty statement.
                    // The problem is that ';' can show up in far too many contexts, and if we see one
                    // and assume it's a statement, then we may bail out inappropriately from whatever
                    // we're parsing.  For example, if we have a semicolon in the middle of a class, then
                    // we really don't want to assume the class is over and we're on a statement in the
                    // outer module.  We just want to consume and move on.
                    return !(token() === SyntaxKind.SemicolonToken && inErrorRecovery) && isStartOfStatement() && token() !== SyntaxKind.DotDotDotToken;
                case ParsingContext.SwitchClauses:
                    return token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword;
                case ParsingContext.TypeMembers:
                case ParsingContext.返回值类型成员_:
                case ParsingContext.对象体成员_:
                    return lookAhead(isTypeMemberStart);
                case ParsingContext.EnumMembers:
                    // Include open bracket computed properties. This technically also lets in indexers,
                    // which would be a candidate for improved error reporting.
                    return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName();
                case ParsingContext.初始化成员_:
                    return isStartOfExpression();
                case ParsingContext.ObjectLiteralMembers:
                    switch (token()) {
                        case SyntaxKind.OpenBracketToken:
                        case SyntaxKind.AsteriskToken:
                        case SyntaxKind.DotDotDotToken:
                        case SyntaxKind.DotToken: // Not an object literal member, but don't want to close the object (see `tests/cases/fourslash/completionsDotInObjectLiteral.ts`)
                            return true;
                        default:
                            return isLiteralPropertyName();
                    }
                case ParsingContext.HeritageClauseElement:
                    // If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{`
                    // That way we won't consume the body of a class in its heritage clause.
                    if (token() === SyntaxKind.OpenBraceToken) {
                        return lookAhead(isValidHeritageClauseObjectLiteral);
                    }

                    if (!inErrorRecovery) {
                        return isStartOfLeftHandSideExpression() && !isHeritageClauseExtendsOrImplementsKeyword();
                    }
                    else {
                        // If we're in error recovery we tighten up what we're willing to match.
                        // That way we don't treat something like "this" as a valid heritage clause
                        // element during recovery.
                        return isIdentifier() && !isHeritageClauseExtendsOrImplementsKeyword();
                    }
                case ParsingContext.VariableDeclarations:
                    return isIdentifierOrPattern();
                case ParsingContext.TypeParameters:
                    return isIdentifier();
                case ParsingContext.ArrayLiteralMembers:
                    switch (token()) {
                        case SyntaxKind.CommaToken:
                        case SyntaxKind.DotToken: // Not an array literal member, but don't want to close the array (see `tests/cases/fourslash/completionsDotInArrayLiteralInObjectLiteral.ts`)
                            return true;
                    }
                // falls through
                case ParsingContext.ArgumentExpressions:
                    return isStartOfExpression();
                case ParsingContext.Parameters:
                    return isStartOfParameter(/*isJSDocParameter*/ false);
                case ParsingContext.JSDocParameters:
                    return isStartOfParameter(/*isJSDocParameter*/ true);
                case ParsingContext.TypeArguments:
                case ParsingContext.TupleElementTypes:
                    return token() === SyntaxKind.CommaToken || isStartOfType();
                case ParsingContext.HeritageClauses:
                    return isHeritageClause();
            }

            return Debug.fail("Non-exhaustive case in 'isListElement'.");
        }

        function isValidHeritageClauseObjectLiteral() {
            Debug.assert(token() === SyntaxKind.OpenBraceToken);
            if (nextToken() === SyntaxKind.CloseBraceToken) {
                // if we see "extends {}" then only treat the {} as what we're extending (and not
                // the class body) if we have:
                //
                //      extends {} {
                //      extends {},
                //      extends {} extends
                //      extends {} implements

                const next = nextToken();
                return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ColonToken;
            }

            return true;
        }

        function nextTokenIsIdentifier() {
            nextToken();
            return isIdentifier();
        }

        function isHeritageClauseExtendsOrImplementsKeyword(): boolean {
            if (token() === SyntaxKind.ColonToken) {

                return lookAhead(nextTokenIsStartOfExpression);
            }

            return false;
        }

        function nextTokenIsStartOfExpression() {
            nextToken();
            return isStartOfExpression();
        }

        function nextTokenIsStartOfType() {
            nextToken();
            return isStartOfType();
        }

        // True if positioned at a list terminator
        function isListTerminator(kind: ParsingContext): boolean {
            if (token() === SyntaxKind.EndOfFileToken) {
                // Being at the end of the file ends all lists.
                return true;
            }

            switch (kind) {
                case ParsingContext.源码顶级语句_:
                    return !(是源码顶级语句开始() || 是程序集顶级语句());
                case ParsingContext.程序集顶级语句_:
                    return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken;
                case ParsingContext.返回值类型成员_:
                    return token() !== SyntaxKind.CommaToken
                case ParsingContext.初始化成员_:
                    return token() === SyntaxKind.CloseParenToken;
                case ParsingContext.BlockStatements:
                case ParsingContext.SwitchClauses:
                case ParsingContext.TypeMembers:
                case ParsingContext.EnumMembers:
                case ParsingContext.ObjectLiteralMembers:
                case ParsingContext.对象体成员_:
                case ParsingContext.解析导入语句_:
                case ParsingContext.解析导入从语句_:
                    return token() === SyntaxKind.CloseBraceToken;
                case ParsingContext.SwitchClauseStatements:
                    return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword;
                case ParsingContext.HeritageClauseElement:
                    return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ColonToken;
                case ParsingContext.VariableDeclarations:
                    return isVariableDeclaratorListTerminator();
                case ParsingContext.TypeParameters:
                    // Tokens other than '>' are here for better error recovery
                    return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ColonToken;
                case ParsingContext.ArgumentExpressions:
                    // Tokens other than ')' are here for better error recovery
                    return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.SemicolonToken;
                case ParsingContext.ArrayLiteralMembers:
                case ParsingContext.TupleElementTypes:
                    return contextFlags & NodeFlags.JsonFile ? token() === SyntaxKind.CloseBracketToken : token() === SyntaxKind.CloseBracketToken || token() === SyntaxKind.CloseBraceToken;
                case ParsingContext.JSDocParameters:
                case ParsingContext.Parameters:
                    // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
                    return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken || token() === SyntaxKind.ColonEqualsToken;
                case ParsingContext.TypeArguments:
                    // All other tokens should cause the type-argument to terminate except comma token
                    return token() !== SyntaxKind.CommaToken;
                case ParsingContext.HeritageClauses:
                    return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.CloseBraceToken;
                default:
                    return false;
            }
        }

        function isVariableDeclaratorListTerminator(): boolean {
            // If we can consume a semicolon (either explicitly, or with ASI), then consider us done
            // with parsing the list of variable declarators.
            if (canParseSemicolon()) {
                return true;
            }

            // in the case where we're parsing the variable declarator of a 'for-in' statement, we
            // are done if we see an 'in' keyword in front of us. Same with for-of
            if (isInOrOfKeyword(token())) {
                return true;
            }

            // ERROR RECOVERY TWEAK:
            // For better error recovery, if we see an '=>' then we just stop immediately.  We've got an
            // arrow function here and it's going to be very unlikely that we'll resynchronize and get
            // another variable declaration.
            if (token() === SyntaxKind.EqualsGreaterThanToken) {
                return true;
            }

            // Keep trying to parse out variable declarators.
            return false;
        }

        // True if positioned at element or terminator of the current list or any enclosing list
        function isInSomeParsingContext(): boolean {
            for (let kind = 0; kind < ParsingContext.Count; kind++) {
                if (parsingContext & (1 << kind)) {
                    if (isListElement(kind, /*inErrorRecovery*/ true) || isListTerminator(kind)) {
                        return true;
                    }
                }
            }

            return false;
        }

        // Parses a list of elements
        function parseList<T extends Node>(kind: ParsingContext, parseElement: () => T): NodeArray<T> {
            const saveParsingContext = parsingContext;
            parsingContext |= 1 << kind;
            const list = [];
            const listPos = getNodePos();

            while (!isListTerminator(kind)) {
                if (isListElement(kind, /*inErrorRecovery*/ false)) {
                    const element = parseListElement(parseElement);
                    list.push(element);
                    continue;
                }

                if (abortParsingListOrMoveToNextToken(kind)) {
                    break;
                }
            }

            parsingContext = saveParsingContext;
            return createNodeArray(list, listPos);
        }
        // H
        function parseListElement<T extends Node>(parseElement: () => T): T {
            return parseElement();
        }

        // Returns true if we should abort parsing.
        function abortParsingListOrMoveToNextToken(kind: ParsingContext) {
            parseErrorAtCurrentToken(parsingContextErrors(kind));
            if (isInSomeParsingContext()) {
                return true;
            }
            nextToken();
            return false;
        }

        // Parses a comma-delimited list of elements
        function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<T> {
            const saveParsingContext = parsingContext;
            parsingContext |= 1 << kind;
            const list = [];
            const listPos = getNodePos();

            let commaStart = -1; // Meaning the previous token was not a comma
            while (true) {
                if (isListElement(kind, /*inErrorRecovery*/ false)) {
                    const startPos = scanner.getStartPos();
                    list.push(parseListElement(parseElement));
                    commaStart = scanner.getTokenPos();
                    if (parseOptional(SyntaxKind.CommaToken)) {
                        // No need to check for a zero length node since we know we parsed a comma
                        continue;
                    }

                    commaStart = -1; // Back to the state where the last token was not a comma
                    if (isListTerminator(kind)) {
                        break;
                    }

                    // We didn't get a comma, and the list wasn't terminated, explicitly parse
                    // out a comma so we give a good error message.
                    parseExpected(SyntaxKind.CommaToken, getExpectedCommaDiagnostic(kind));

                    // If the token was a semicolon, and the caller allows that, then skip it and
                    // continue.  This ensures we get back on track and don't result in tons of
                    // parse errors.  For example, this can happen when people do things like use
                    // a semicolon to delimit object literal members.   Note: we'll have already
                    // reported an error when we called parseExpected above.
                    if (considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) {
                        nextToken();
                    }
                    if (startPos === scanner.getStartPos()) {
                        // What we're parsing isn't actually remotely recognizable as a element and we've consumed no tokens whatsoever
                        // Consume a token to advance the parser in some way and avoid an infinite loop
                        // This can happen when we're speculatively parsing parenthesized expressions which we think may be arrow functions,
                        // or when a modifier keyword which is disallowed as a parameter name (ie, `static` in strict mode) is supplied
                        nextToken();
                    }
                    continue;
                }

                if (isListTerminator(kind)) {
                    break;
                }

                if (abortParsingListOrMoveToNextToken(kind)) {
                    break;
                }
            }

            parsingContext = saveParsingContext;
            const result = createNodeArray(list, listPos);
            // Recording the trailing comma is deliberately done after the previous
            // loop, and not just if we see a list terminator. This is because the list
            // may have ended incorrectly, but it is still important to know if there
            // was a trailing comma.
            // Check if the last token was a comma.
            if (commaStart >= 0) {
                // Always preserve a trailing comma by marking it on the NodeArray
                result.hasTrailingComma = true;
            }
            return result;
        }

        function getExpectedCommaDiagnostic(kind: ParsingContext) {
            return kind === ParsingContext.EnumMembers ? Diagnostics.An_enum_member_name_must_be_followed_by_a_or : undefined;
        }

        interface MissingList<T extends Node> extends NodeArray<T> {
            isMissingList: true;
        }

        function createMissingList<T extends Node>(): MissingList<T> {
            const list = createNodeArray<T>([], getNodePos()) as MissingList<T>;
            list.isMissingList = true;
            return list;
        }

        function isMissingList(arr: NodeArray<Node>): boolean {
            return !!(arr as MissingList<Node>).isMissingList;
        }

        function parseBracketedList<T extends Node>(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray<T> {
            if (parseExpected(open)) {
                const result = parseDelimitedList(kind, parseElement);
                parseExpected(close);
                return result;
            }

            return createMissingList<T>();
        }

        function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName {
            let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage);
            let dotPos = scanner.getStartPos();
            while (parseOptional(SyntaxKind.DotToken)) {
                if (token() === SyntaxKind.LessThanToken) {
                    // the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting
                    entity.jsdocDotPos = dotPos;
                    break;
                }
                dotPos = scanner.getStartPos();
                entity = createQualifiedName(entity, parseRightSideOfDot(allowReservedWords));
            }
            return entity;
        }

        function createQualifiedName(entity: EntityName, name: Identifier): QualifiedName {
            const node = createNode(SyntaxKind.QualifiedName, entity.pos) as QualifiedName;
            node.left = entity;
            node.right = name;
            return finishNode(node);
        }

        function parseRightSideOfDot(allowIdentifierNames: boolean): Identifier {
            // Technically a keyword is valid here as all identifiers and keywords are identifier names.
            // However, often we'll encounter this in error situations when the identifier or keyword
            // is actually starting another valid construct.
            //
            // So, we check for the following specific case:
            //
            //      name.
            //      identifierOrKeyword identifierNameOrKeyword
            //
            // Note: the newlines are important here.  For example, if that above code
            // were rewritten into:
            //
            //      name.identifierOrKeyword
            //      identifierNameOrKeyword
            //
            // Then we would consider it valid.  That's because ASI would take effect and
            // the code would be implicitly: "name.identifierOrKeyword; identifierNameOrKeyword".
            // In the first case though, ASI will not take effect because there is not a
            // line terminator after the identifier or keyword.
            if (scanner.hasPrecedingLineBreak() && tokenIsIdentifierOrKeyword(token())) {
                const matchesPattern = lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine);

                if (matchesPattern) {
                    // Report that we need an identifier.  However, report it right after the dot,
                    // and not on the next token.  This is because the next token might actually
                    // be an identifier and the error would be quite confusing.
                    return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);
                }
            }

            return allowIdentifierNames ? parseIdentifierName() : parseIdentifier();
        }

        function parseTemplateExpression(): TemplateExpression {
            const template = <TemplateExpression>createNode(SyntaxKind.TemplateExpression);

            template.head = parseTemplateHead();
            Debug.assert(template.head.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind");

            const list = [];
            const listPos = getNodePos();

            do {
                list.push(parseTemplateSpan());
            }
            while (last(list).literal.kind === SyntaxKind.TemplateMiddle);

            template.templateSpans = createNodeArray(list, listPos);
            const templateLast = lastOrUndefined(template.templateSpans);
            template.文本后缀 = templateLast&&templateLast.literal.文本后缀 || 0;
            return finishNode(template);
        }

        function parseTemplateSpan(): TemplateSpan {
            const span = <TemplateSpan>createNode(SyntaxKind.TemplateSpan);
            span.expression = parseExpression();

            let literal: TemplateMiddle | TemplateTail;
            if (token() === SyntaxKind.CloseBraceToken) {
                reScanTemplateToken();
                literal = parseTemplateMiddleOrTemplateTail();
            }
            else {
                literal = <TemplateTail>parseExpectedToken(SyntaxKind.TemplateTail, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken));
            }

            span.literal = literal;
            return finishNode(span);
        }

        function parseLiteralNode(): LiteralExpression {
            return <LiteralExpression>parseLiteralLikeNode(token());
        }

        function parseTemplateHead(): TemplateHead {
            const fragment = parseLiteralLikeNode(token());
            Debug.assert(fragment.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind");
            return <TemplateHead>fragment;
        }

        function parseTemplateMiddleOrTemplateTail(): TemplateMiddle | TemplateTail {
            const fragment = parseLiteralLikeNode(token());
            Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind");
            return <TemplateMiddle | TemplateTail>fragment;
        }

        function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode {
            const node = <LiteralLikeNode>createNode(kind);
            node.text = scanner.getTokenValue();
            switch (kind) {
                case SyntaxKind.NoSubstitutionTemplateLiteral:
                case SyntaxKind.TemplateHead:
                case SyntaxKind.TemplateMiddle:
                case SyntaxKind.TemplateTail:
                    const isLast = kind === SyntaxKind.NoSubstitutionTemplateLiteral || kind === SyntaxKind.TemplateTail;
                    const tokenText = scanner.getTokenText();
                    (<TemplateLiteralLikeNode>node).rawText = tokenText.substring(1, tokenText.length - (scanner.isUnterminated() ? 0 : isLast ? 1 : 2));
                    break;
            }

            if (scanner.hasExtendedUnicodeEscape()) {
                node.hasExtendedUnicodeEscape = true;
            }

            if (scanner.isUnterminated()) {
                node.isUnterminated = true;
            }

            // Octal literals are not allowed in strict mode or ES5
            // Note that theoretically the following condition would hold true literals like 009,
            // which is not octal.But because of how the scanner separates the tokens, we would
            // never get a token like this. Instead, we would get 00 and 9 as two separate tokens.
            // We also do not need to check for negatives because any prefix operator would be part of a
            // parent unary expression.
            if (node.kind === SyntaxKind.NumericLiteral) {
                (<NumericLiteral>node).numericLiteralFlags = scanner.getTokenFlags() & TokenFlags.NumericLiteralFlags;
            }
            if (node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.字符字面量_ || node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail) {
                (<StringLiteral | NoSubstitutionTemplateLiteral | 字符字面量_>node).文本后缀 = scanner.getTokenFlags() & TokenFlags.文本后缀标志_;
            }

            nextToken();
            finishNode(node);

            return node;
        }

        // TYPES

        function parseTypeReference(): TypeReferenceNode {
            const node = <TypeReferenceNode>createNode(SyntaxKind.TypeReference);
            node.typeName = parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected);
            if (!scanner.hasPrecedingLineBreak() && !node.typeName.jsdocDotPos && reScanLessThanToken() === SyntaxKind.LessThanToken) {
                node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
            }
            return finishNode(node);
        }

        // If true, we should abort parsing an error function.
        function typeHasArrowFunctionBlockingParseError(node: TypeNode): boolean {
            switch (node.kind) {
                case SyntaxKind.TypeReference:
                    return nodeIsMissing((node as TypeReferenceNode).typeName);
                case SyntaxKind.FunctionType: {
                    const { parameters, type } = node as FunctionTypeNode;
                    return isMissingList(parameters) || typeHasArrowFunctionBlockingParseError(type);
                }
                case SyntaxKind.ParenthesizedType:
                    return typeHasArrowFunctionBlockingParseError((node as ParenthesizedTypeNode).type);
                default:
                    return false;
            }
        }

        function parseJSDocAllType(postFixEquals: boolean): JSDocAllType | JSDocOptionalType {
            const result = createNode(SyntaxKind.JSDocAllType) as JSDocAllType;
            if (postFixEquals) {
                return createPostfixType(SyntaxKind.JSDocOptionalType, result) as JSDocOptionalType;
            }
            else {
                nextToken();
            }
            return finishNode(result);
        }

        function parseJSDocNonNullableType(): TypeNode {
            const result = createNode(SyntaxKind.JSDocNonNullableType) as JSDocNonNullableType;
            nextToken();
            result.type = parseNonArrayType();
            return finishNode(result);
        }

        function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType {
            const pos = scanner.getStartPos();
            // skip the ?
            nextToken();

            // Need to lookahead to decide if this is a nullable or unknown type.

            // Here are cases where we'll pick the unknown type:
            //
            //      Foo(?,
            //      { a: ? }
            //      Foo(?)
            //      Foo<?>
            //      Foo(?=
            //      (?|
            if (token() === SyntaxKind.CommaToken ||
                token() === SyntaxKind.CloseBraceToken ||
                token() === SyntaxKind.CloseParenToken ||
                token() === SyntaxKind.GreaterThanToken ||
                token() === SyntaxKind.EqualsToken ||
                token() === SyntaxKind.BarToken) {

                const result = <JSDocUnknownType>createNode(SyntaxKind.JSDocUnknownType, pos);
                return finishNode(result);
            }
            else {
                const result = <JSDocNullableType>createNode(SyntaxKind.JSDocNullableType, pos);
                result.type = parseType();
                return finishNode(result);
            }
        }

        function parseJSDocFunctionType(): JSDocFunctionType | TypeReferenceNode {
            if (lookAhead(nextTokenIsOpenParen)) {
                const result = <JSDocFunctionType>createNodeWithJSDoc(SyntaxKind.JSDocFunctionType);
                nextToken();
                fillSignature(SyntaxKind.ColonToken, SignatureFlags.Type | SignatureFlags.JSDoc, result);
                return finishNode(result);
            }
            const node = <TypeReferenceNode>createNode(SyntaxKind.TypeReference);
            node.typeName = parseIdentifierName();
            return finishNode(node);
        }

        function parseJSDocParameter(): ParameterDeclaration {
            const parameter = createNode(SyntaxKind.Parameter) as ParameterDeclaration;
            if (token() === SyntaxKind.ThisKeyword || token() === SyntaxKind.NewKeyword) {
                parameter.name = parseIdentifierName();
                parseExpected(SyntaxKind.ColonToken);
            }
            parameter.type = parseJSDocType();
            return finishNode(parameter);
        }

        function parseJSDocType(): TypeNode {
            scanner.setInJSDocType(true);

            const dotdotdot = parseOptionalToken(SyntaxKind.DotDotDotToken);
            let type = parseType();
            scanner.setInJSDocType(false);
            if (dotdotdot) {
                const variadic = createNode(SyntaxKind.JSDocVariadicType, dotdotdot.pos) as JSDocVariadicType;
                variadic.type = type;
                type = finishNode(variadic);
            }
            if (token() === SyntaxKind.EqualsToken) {
                return createPostfixType(SyntaxKind.JSDocOptionalType, type);
            }
            return type;
        }

        function parseTypeParameter(): TypeParameterDeclaration {
            const node = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter);
            node.name = parseIdentifier();
            if (parseOptional(SyntaxKind.ColonToken)) {
                // It's not uncommon for people to write improper constraints to a generic.  If the
                // user writes a constraint that is an expression and not an actual type, then parse
                // it out as an expression (so we can recover well), but report that a type is needed
                // instead.
                if (isStartOfType() || !isStartOfExpression()) {
                    node.constraint = parseType();
                }
                else {
                    // It was not a type, and it looked like an expression.  Parse out an expression
                    // here so we recover well.  Note: it is important that we call parseUnaryExpression
                    // and not parseExpression here.  If the user has:
                    //
                    //      <T extends "">
                    //
                    // We do *not* want to consume the `>` as we're consuming the expression for "".
                    node.expression = parseUnaryExpressionOrHigher();
                }
            }

            if (parseOptional(SyntaxKind.EqualsToken)) {
                node.default = parseType();
            }
            return finishNode(node);
        }

        function parseTypeParameters(): NodeArray<TypeParameterDeclaration> | undefined {
            if (token() === SyntaxKind.LessThanToken) {
                return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
            }
        }

        function parseParameterType(): TypeNode | undefined {
            if (parseOptional(SyntaxKind.ColonToken)) {
                return parseType();
            }

            return undefined;
        }

        function isStartOfParameter(isJSDocParameter: boolean): boolean {
            return token() === SyntaxKind.DotDotDotToken ||
                isIdentifierOrPattern() ||
                token() === SyntaxKind.AtToken ||
                token() === SyntaxKind.AmpersandToken ||
                isStartOfType(/*inStartOfParameter*/ !isJSDocParameter);
        }

        function parseParameter(): ParameterDeclaration {
            const node = <ParameterDeclaration>createNodeWithJSDoc(SyntaxKind.Parameter);
            if (token() === SyntaxKind.ThisKeyword) {
                node.name = createIdentifier(/*isIdentifier*/ true);
                node.type = parseParameterType();
                return finishNode(node);
            }

            // FormalParameter [Yield,Await]:
            //      BindingElement[?Yield,?Await]

            let 修饰符开始 = 0;
            const li: Token<SyntaxKind.AmpersandToken | SyntaxKind.AtToken>[] = [];
            while (token() === SyntaxKind.AmpersandToken || token() === SyntaxKind.AtToken) {
                if (!修饰符开始) 修饰符开始 = getNodePos();
                li.push(parseTokenNode());
            }
            let 限定符: NodeArray<Token<SyntaxKind.AmpersandToken | SyntaxKind.AtToken>> | undefined = 修饰符开始 ? createNodeArray(li, 修饰符开始) : undefined;
            node.限定符 = 限定符;
            node.name = parseIdentifierOrPattern();
            if (getFullWidth(node.name) === 0) {
                // in cases like
                // 'use strict'
                // function foo(static)
                // isParameter('static') === true, because of isModifier('static')
                // however 'static' is not a legal identifier in a strict mode.
                // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined)
                // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM)
                // to avoid this we'll advance cursor to the next token.
                nextToken();
            }

            node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
            node.type = parseParameterType();
            node.initializer = parseInitializer();

            return finishNode(node);
        }

        /**
         * Note: If returnToken is EqualsGreaterThanToken, `signature.type` will always be defined.
         * @returns If return type parsing succeeds
         */
        function fillSignature(
            returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken,
            flags: SignatureFlags,
            signature: SignatureDeclaration): boolean {
            if (!(flags & SignatureFlags.JSDoc)) {
                signature.typeParameters = parseTypeParameters();
                if(signature.kind === SyntaxKind.FunctionType  && signature.typeParameters){
                    parseErrorAtPosition(signature.typeParameters.pos, signature.typeParameters.end - signature.typeParameters.pos, Diagnostics.此版本未支持此语法);
                }
            }
            const parametersParsedSuccessfully = parseParameterList(signature, flags);
            if (shouldParseReturnType(returnToken, !!(flags & SignatureFlags.Type))) {
                signature.type = parseType();
                if (typeHasArrowFunctionBlockingParseError(signature.type)) return false;
            }
            return parametersParsedSuccessfully;
        }

        function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean {
            if (returnToken === SyntaxKind.EqualsGreaterThanToken) {
                parseExpected(returnToken);
                return true;
            }
            else if (parseOptional(SyntaxKind.ColonToken)) {
                return true;
            }
            else if (isType && token() === SyntaxKind.EqualsGreaterThanToken) {
                // This is easy to get backward, especially in type contexts, so parse the type anyway
                parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken));
                nextToken();
                return true;
            }
            return false;
        }

        // Returns true on success.
        function parseParameterList(signature: SignatureDeclaration, flags: SignatureFlags): boolean {
            // FormalParameters [Yield,Await]: (modified)
            //      [empty]
            //      FormalParameterList[?Yield,Await]
            //
            // FormalParameter[Yield,Await]: (modified)
            //      BindingElement[?Yield,Await]
            //
            // BindingElement [Yield,Await]: (modified)
            //      SingleNameBinding[?Yield,?Await]
            //      BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
            //
            // SingleNameBinding [Yield,Await]:
            //      BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
            if (!parseExpected(SyntaxKind.OpenParenToken)) {
                signature.parameters = createMissingList<ParameterDeclaration>();
                return false;
            }

            signature.parameters = flags & SignatureFlags.JSDoc ?
                parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) :
                parseDelimitedList(ParsingContext.Parameters, parseParameter);

            return parseExpected(SyntaxKind.CloseParenToken);
        }

        function parseTypeMemberSemicolon() {
            // We allow type members to be separated by commas or (possibly ASI) semicolons.
            // First check if it was a comma.  If so, we're done with the member.
            if (parseOptional(SyntaxKind.CommaToken)) {
                return;
            }

            // Didn't have a comma.  We must have a (possible ASI) semicolon.
            parseSemicolon();
        }

        function parsePropertyOrMethodSignature(node: PropertySignature | MethodSignature): PropertySignature | MethodSignature {
            node.name = parsePropertyName();
            node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
            if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
                node.kind = SyntaxKind.MethodSignature;
                // Method signatures don't exist in expression contexts.  So they have neither
                // [Yield] nor [Await]
                fillSignature(SyntaxKind.ColonToken, SignatureFlags.Type, <MethodSignature>node);
            }
            else {
                node.kind = SyntaxKind.PropertySignature;
                node.type = parseTypeAnnotation();
                if (token() === SyntaxKind.EqualsToken) {
                    // Although type literal properties cannot not have initializers, we attempt
                    // to parse an initializer so we can report in the checker that an interface
                    // property or type literal property cannot have an initializer.
                    (<PropertySignature>node).initializer = parseInitializer();
                }
            }
            if (!inContext(NodeFlags.在返回值类型上下文_)) parseTypeMemberSemicolon();
            if (inContext(NodeFlags.禁止属性签名上下文_) && isPropertySignature(node)) {
                parseErrorAtPosition(node.pos, scanner.getStartPos() - node.pos, Diagnostics.接口声明不能包含属性签名_0, ts.isIdentifier(node.name) ? node.name.escapedText : node.name.text);
            }

            if (inContext(NodeFlags.禁止方法签名上下文_) && isMethodSignature(node)) {
                parseErrorAtPosition(node.pos, scanner.getStartPos() - node.pos, Diagnostics.对象声明不能包含方法签名_0, ts.isIdentifier(node.name) ? node.name.escapedText : node.name.text);
            }
            return finishNode(node);
        }

        function 解析属性或内部方法声明(): PropertyDeclaration | 内部方法声明_ | ConstructSignatureDeclaration | ConstructDeclaration | 释放声明_ {
            const node = <PropertyDeclaration | ConstructDeclaration | 释放声明_ | 内部方法声明_>createNodeWithJSDoc(SyntaxKind.Unknown);
            if (contextFlags & NodeFlags.Ambient && token() === SyntaxKind.构建关键字_) {
                return parseSignatureMember(SyntaxKind.ConstructSignature);
            }
            if (token() === SyntaxKind.构建关键字_) {
                parseExpected(SyntaxKind.构建关键字_);
                return 解析构建声明(<ConstructDeclaration>node);
            }
            if (token() === SyntaxKind.释放关键字_) {
                parseExpected(SyntaxKind.释放关键字_);
                return 解析释放声明(<释放声明_>node);
            }
            node.name = parsePropertyName();
            node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
            if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
                return 解析内部方法(<内部方法声明_>node, Diagnostics.or_expected);
            }
            return parsePropertyDeclaration(<PropertyDeclaration>node);
        }

        function 仅解析内部方法声明(): 内部方法声明_ {
            const node = <内部方法声明_>createNodeWithJSDoc(SyntaxKind.内部方法声明_);
            node.name = parseIdentifier();
            node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
            return 解析内部方法(<内部方法声明_>node, Diagnostics.or_expected);
        }

        function 解析构建声明(node: ConstructDeclaration, diagnosticMessage?: DiagnosticMessage): ConstructDeclaration {
            node.kind = SyntaxKind.ConstructDeclaration;
            fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
            禁止返回表达式 = true;
            允许基类调用 = true;
            node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None, diagnosticMessage);
            允许基类调用 = false;
            禁止返回表达式 = false;
            return finishNode(node);
        }

        function 解析释放声明(node: 释放声明_, diagnosticMessage?: DiagnosticMessage): 释放声明_ {
            node.kind = SyntaxKind.释放声明_;
            fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
            禁止返回表达式 = true;
            node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None, diagnosticMessage);
            禁止返回表达式 = false;
            return finishNode(node);
        }

        function 解析内部方法(node: 内部方法声明_, diagnosticMessage?: DiagnosticMessage): 内部方法声明_ {
            node.kind = SyntaxKind.内部方法声明_;
            fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
            node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None, diagnosticMessage);
            return finishNode(node);
        }

        function parsePropertyDeclaration(node: PropertyDeclaration): PropertyDeclaration {
            node.kind = SyntaxKind.PropertyDeclaration;
            if (!node.questionToken && token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
                node.exclamationToken = parseTokenNode<Token<SyntaxKind.ExclamationToken>>();
            }
            node.type = parseTypeAnnotation();
            node.initializer = parseInitializer();
            parseSemicolon();
            return finishNode(node);
        }

        function isTypeMemberStart(): boolean {
            // Return true if we have the start of a signature member
            if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.LessThanToken) {
                return true;
            }
            let idToken = false;
            // Index signatures and computed property names are type members
            if (token() === SyntaxKind.OpenBracketToken) {
                return true;
            }
            // Try to get the first property-like token following all modifiers
            if (isLiteralPropertyName()) {
                idToken = true;
                nextToken();
            }
            // If we were able to get any potential identifier, check that it is
            // the start of a member declaration
            if (idToken) {
                return token() === SyntaxKind.OpenParenToken ||
                    token() === SyntaxKind.LessThanToken ||
                    token() === SyntaxKind.QuestionToken ||
                    token() === SyntaxKind.ColonToken ||
                    token() === SyntaxKind.CommaToken ||
                    canParseSemicolon();
            }
            return false;
        }

        function parseTypeMember(): TypeElement {
            const node = <TypeElement>createNodeWithJSDoc(SyntaxKind.Unknown);
            if (token() === SyntaxKind.构建关键字_ && lookAhead(nextTokenIsOpenParenOrLessThan)) {
                return parseSignatureMember(SyntaxKind.ConstructSignature);
            }
            return parsePropertyOrMethodSignature(<PropertySignature | MethodSignature>node);
        }
        
        function nextTokenIsOpenParenOrLessThan() {
            nextToken();
            return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken;
        }

        function parseSignatureMember(kind: SyntaxKind.ConstructSignature): ConstructSignatureDeclaration {
            const node = <ConstructSignatureDeclaration>createNodeWithJSDoc(kind);
            if (kind === SyntaxKind.ConstructSignature) {
                parseExpected(SyntaxKind.构建关键字_);
            }
            fillSignature(SyntaxKind.ColonToken, SignatureFlags.Type, node);
            parseTypeMemberSemicolon();
            return finishNode(node);
        }

        function parseObjectTypeMembers(): NodeArray<TypeElement> {
            let members: NodeArray<TypeElement>;
            if (parseExpected(SyntaxKind.OpenBraceToken)) {
                members = parseList(ParsingContext.TypeMembers, parseTypeMember);
                parseExpected(SyntaxKind.CloseBraceToken);
            }
            else {
                members = createMissingList<TypeElement>();
            }

            return members;
        }

        function parseParenthesizedType(): TypeNode {
            const node = <ParenthesizedTypeNode>createNode(SyntaxKind.ParenthesizedType);
            parseExpected(SyntaxKind.OpenParenToken);
            node.type = parseType();
            parseExpected(SyntaxKind.CloseParenToken);
            return finishNode(node);
        }

        function parseFunctionOrConstructorType(): TypeNode {
            const pos = getNodePos();
            const kind = SyntaxKind.FunctionType;
            const node = <FunctionTypeNode>createNodeWithJSDoc(kind, pos);
            fillSignature(SyntaxKind.EqualsGreaterThanToken, SignatureFlags.Type, node);
            return finishNode(node);
        }

        function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode {
            const node = createNode(SyntaxKind.LiteralType) as LiteralTypeNode;
            let unaryMinusExpression!: PrefixUnaryExpression;
            if (negative) {
                unaryMinusExpression = createNode(SyntaxKind.PrefixUnaryExpression) as PrefixUnaryExpression;
                unaryMinusExpression.operator = SyntaxKind.MinusToken;
                nextToken();
            }
            let expression: BooleanLiteral | LiteralExpression | PrefixUnaryExpression = token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword
                ? parseTokenNode<BooleanLiteral>()
                : parseLiteralLikeNode(token()) as LiteralExpression;
            if (negative) {
                unaryMinusExpression.operand = expression;
                finishNode(unaryMinusExpression);
                expression = unaryMinusExpression;
            }
            node.literal = expression;
            return finishNode(node);
        }

        function 下个令牌是数值字面量() {
            nextToken();
            const kind = token();
            switch (kind) {
                case SyntaxKind.NumericLiteral:
                case SyntaxKind.BigIntLiteral:
                    return true;
            }
            return false;
        }

        function 应该是类型转换表达式的类型节点() {
            const tn = 尝试解析字面量类型头部类型节点();
            if (tn && token() === SyntaxKind.点左括号_) {
                return true;
            }
        }

        function 下个令牌是类型的开始() {
            nextToken();
            return isStartOfType();
        }

        function parseNonArrayType(): TypeNode {
            switch (token()) {
                case SyntaxKind.TypeKeyword:
                case SyntaxKind.整数关键字_:
                case SyntaxKind.AnyKeyword:
                case SyntaxKind.StringKeyword:
                case SyntaxKind.文本8_:
                case SyntaxKind.文本16_:
                case SyntaxKind.文本32_:
                case SyntaxKind.BooleanKeyword:
                case SyntaxKind.VoidKeyword:
                case SyntaxKind.NullKeyword:
                case SyntaxKind.指针关键字_:
                case SyntaxKind.正量关键字_:
                case SyntaxKind.小数关键字_:
                case SyntaxKind.正整数关键字_:
                case SyntaxKind.整数8_:
                case SyntaxKind.整数16_:
                case SyntaxKind.整数32_:
                case SyntaxKind.整数64_:
                case SyntaxKind.正整数8_:
                case SyntaxKind.正整数16_:
                case SyntaxKind.正整数32_:
                case SyntaxKind.正整数64_:
                case SyntaxKind.小数32_:
                case SyntaxKind.小数64_:
                case SyntaxKind.虚数32_:
                case SyntaxKind.虚数64_:
                case SyntaxKind.复数64_:
                case SyntaxKind.复数128_:
                case SyntaxKind.字符_:
                case SyntaxKind.字符8_:
                case SyntaxKind.字符16_:
                case SyntaxKind.字符32_:
                case SyntaxKind.字节_:
                    return parseTokenNode<TypeNode>();
                case SyntaxKind.MinusToken:
                    return lookAhead(下个令牌是数值字面量) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference();
                case SyntaxKind.AsteriskToken:
                    return parseJSDocAllType(/*postfixEquals*/ false);
                case SyntaxKind.AsteriskEqualsToken:
                    return parseJSDocAllType(/*postfixEquals*/ true);
                case SyntaxKind.QuestionToken:
                    return parseJSDocUnknownOrNullableType();
                case SyntaxKind.FunctionKeyword:
                    return parseJSDocFunctionType();
                case SyntaxKind.ExclamationToken:
                    return parseJSDocNonNullableType();
                case SyntaxKind.NumericLiteral:
                    const temp = parseLiteralTypeNode();
                    if (parseOptional(SyntaxKind.TildeToken)) {
                        const temp2 = tryParse(parseLiteralTypeNode);
                        const 区间类型节点_ = createNode(SyntaxKind.区间类型节点_, temp.pos) as 区间类型节点_;
                        区间类型节点_.开始 = temp;
                        区间类型节点_.结束 = temp2;
                        return finishNode(区间类型节点_);
                    }
                    else {
                        return temp;
                    }
                case SyntaxKind.NoSubstitutionTemplateLiteral:
                case SyntaxKind.StringLiteral:
                case SyntaxKind.字符字面量_:
                case SyntaxKind.BigIntLiteral:
                case SyntaxKind.TrueKeyword:
                case SyntaxKind.FalseKeyword:
                    return parseLiteralTypeNode();
                case SyntaxKind.OpenParenToken:
                    return parseParenthesizedType();
                case SyntaxKind.只读关键字_: {
                    const tn = <类型限定符类型节点_>createNode(SyntaxKind.类型限定类型_);
                    tn.限定符 = parseTokenNode<只读令牌_>();
                    tn.type = token() === SyntaxKind.OpenParenToken? parseParenthesizedType() : parseType();
                    return finishNode(tn);
                }
                case SyntaxKind.恒定关键字_: {
                    const tn = <类型限定符类型节点_>createNode(SyntaxKind.类型限定类型_);
                    tn.限定符 = parseTokenNode<恒定令牌_>();
                    tn.type = token() === SyntaxKind.OpenParenToken? parseParenthesizedType() : parseType();
                    return finishNode(tn);
                }
                default:
                    return parseTypeReference();
            }
        }

        function isStartOfType(inStartOfParameter?: boolean): boolean {
            switch (token()) {
                case SyntaxKind.AnyKeyword:
                case SyntaxKind.StringKeyword:
                case SyntaxKind.文本8_:
                case SyntaxKind.文本16_:
                case SyntaxKind.文本32_:
                case SyntaxKind.BooleanKeyword:
                case SyntaxKind.VoidKeyword:
                case SyntaxKind.NullKeyword:
                case SyntaxKind.ThisKeyword:

                case SyntaxKind.OpenBracketToken:
                case SyntaxKind.LessThanToken:
                case SyntaxKind.BarToken:
                case SyntaxKind.AmpersandToken:
                case SyntaxKind.StringLiteral:
                case SyntaxKind.字符字面量_:
                case SyntaxKind.NumericLiteral:

                case SyntaxKind.BigIntLiteral:
                case SyntaxKind.TrueKeyword:
                case SyntaxKind.FalseKeyword:
                case SyntaxKind.AsteriskToken:

                case SyntaxKind.DotDotDotToken:

                case SyntaxKind.指针关键字_:
                case SyntaxKind.正量关键字_:
                case SyntaxKind.整数关键字_:
                case SyntaxKind.小数关键字_:
                case SyntaxKind.正整数关键字_:
                case SyntaxKind.整数8_:
                case SyntaxKind.整数16_:
                case SyntaxKind.整数32_:
                case SyntaxKind.整数64_:
                case SyntaxKind.正整数8_:
                case SyntaxKind.正整数16_:
                case SyntaxKind.正整数32_:
                case SyntaxKind.正整数64_:
                case SyntaxKind.小数32_:
                case SyntaxKind.小数64_:
                case SyntaxKind.虚数32_:
                case SyntaxKind.虚数64_:
                case SyntaxKind.复数64_:
                case SyntaxKind.复数128_:
                case SyntaxKind.字符_:
                case SyntaxKind.字符8_:
                case SyntaxKind.字符16_:
                case SyntaxKind.字符32_:
                case SyntaxKind.字节_:
                    return true;
                case SyntaxKind.恒定关键字_:
                case SyntaxKind.只读关键字_:
                    return lookAhead(下个令牌是类型的开始);
                case SyntaxKind.FunctionKeyword:
                    return !inStartOfParameter;
                case SyntaxKind.MinusToken:
                    return !inStartOfParameter && lookAhead(下个令牌是数值字面量);
                case SyntaxKind.OpenParenToken:
                    // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier,
                    // or something that starts a type. We don't want to consider things like '(1)' a type.
                    return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType);
                default:
                    return isIdentifier();
            }
        }

        function isStartOfParenthesizedOrFunctionType() {
            nextToken();
            return token() === SyntaxKind.CloseParenToken || isStartOfParameter(/*isJSDocParameter*/ false) || isStartOfType();
        }

        function parsePostfixTypeOrHigher(): TypeNode {
            let type = parseNonArrayType();
            while (!scanner.hasPrecedingLineBreak()) {
                switch (token()) {
                    case SyntaxKind.ExclamationToken:
                        type = createPostfixType(SyntaxKind.JSDocNonNullableType, type);
                        break;
                    case SyntaxKind.QuestionToken:
                        // If not in JSDoc and next token is start of a type we have a conditional type
                        if (!(contextFlags & NodeFlags.JSDoc) && lookAhead(nextTokenIsStartOfType)) {
                            return type;
                        }
                        type = createPostfixType(SyntaxKind.JSDocNullableType, type);
                        break;
                    case SyntaxKind.OpenBracketToken:
                        parseExpected(SyntaxKind.OpenBracketToken);
                        if (parseOptional(SyntaxKind.CloseBracketToken)) {
                            // 文本[]
                            const node = <动态数组类型节点_>createNode(SyntaxKind.动态数组_, type.pos);
                            node.type = type;
                            type = finishNode(node);
                            break;
                        }

                        if (parseOptional(SyntaxKind.DotDotToken)) {
                            // 文本[..]
                            const node = <ArrayTypeNode>createNode(SyntaxKind.ArrayType, type.pos);
                            node.elementType = type;
                            parseExpected(SyntaxKind.CloseBracketToken);
                            type = finishNode(node);
                            break;
                        }
                        // 文本[3]
                        允许类型计算 = true;
                        const node = <ArrayTypeNode>createNode(SyntaxKind.ArrayType, type.pos);
                        node.elementType = type;
                        node.长度 = parseType();
                        允许类型计算 = false;
                        parseExpected(SyntaxKind.CloseBracketToken);
                        type = finishNode(node);
                        break;
                    case SyntaxKind.DotOpenBracketToken: {
                        // 文本.[整数]
                        parseExpected(SyntaxKind.DotOpenBracketToken);
                        const node = <词典类型节点_>createNode(SyntaxKind.词典类型_, type.pos);
                        node.值类型 = type;
                        node.键类型 = parseType();
                        parseExpected(SyntaxKind.CloseBracketToken);
                        type = finishNode(node);
                        break;
                    }
                    case SyntaxKind.AsteriskToken: {
                        parseExpected(SyntaxKind.AsteriskToken);
                        const node = <指针类型节点_>createNode(SyntaxKind.指针类型_, type.pos);
                        node.type = type;
                        type = finishNode(node);
                        break;
                    }
                    case SyntaxKind.PlusToken:
                    case SyntaxKind.MinusToken:
                    case SyntaxKind.LessThanLessThanToken:
                    case SyntaxKind.GreaterThanGreaterThanToken: {
                        if(允许类型计算){
                            return 编译二元运算类型节点剩余(0, type);
                        }
                    }
                    default:
                        return type;
                }
            }
            return type;
        }

        function createPostfixType(kind: SyntaxKind, type: TypeNode) {
            nextToken();
            const postfix = createNode(kind, type.pos) as OptionalTypeNode | JSDocOptionalType | JSDocNonNullableType | JSDocNullableType;
            postfix.type = type;
            return finishNode(postfix);
        }

        function 解析指针类型节点() {
            const tn = <指针类型节点_>createNode(SyntaxKind.指针类型_);
            parseExpected(SyntaxKind.AsteriskToken);
            tn.type = parseTypeOperatorOrHigher();
            return finishNode(tn);
        }

        function 解析变长参数类型节点() {
            const tn = <变长参数类型节点_>createNode(SyntaxKind.变长参数_)
            parseExpected(SyntaxKind.DotDotDotToken);
            tn.type = parseTypeOperatorOrHigher();
            return finishNode(tn);
        }

        function parseTypeOperatorOrHigher(): TypeNode {
            const k = token();
            switch (k) {
                case SyntaxKind.AsteriskToken:
                    return 解析指针类型节点();
                case SyntaxKind.DotDotDotToken:
                    return 解析变长参数类型节点();
            }
            return parsePostfixTypeOrHigher();
        }

        function parseUnionOrIntersectionType(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, parseConstituentType: () => TypeNode, operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken): TypeNode {
            const start = scanner.getStartPos();
            const hasLeadingOperator = parseOptional(operator);
            let type = parseConstituentType();
            if (token() === operator || hasLeadingOperator) {
                const types = [type];
                while (parseOptional(operator)) {
                    types.push(parseConstituentType());
                }
                const node = <UnionOrIntersectionTypeNode>createNode(kind, start);
                node.types = createNodeArray(types, start);
                type = finishNode(node);
            }
            return type;
        }

        function parseIntersectionTypeOrHigher(): TypeNode {
            return parseUnionOrIntersectionType(SyntaxKind.IntersectionType, parseTypeOperatorOrHigher, SyntaxKind.AmpersandToken);
        }

        function parseUnionTypeOrHigher(): TypeNode {
            return parseUnionOrIntersectionType(SyntaxKind.UnionType, parseIntersectionTypeOrHigher, SyntaxKind.BarToken);
        }

        function isStartOfFunctionType(): boolean {
            if (token() === SyntaxKind.LessThanToken) {
                return true;
            }
            return token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType);
        }

        function skipParameterStart(): boolean {
            if (isIdentifier() || token() === SyntaxKind.ThisKeyword) {
                nextToken();
                return true;
            }
            if (token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken) {
                // Return true if we can parse an array or object binding pattern with no errors
                const previousErrorCount = parseDiagnostics.length;
                parseIdentifierOrPattern();
                return previousErrorCount === parseDiagnostics.length;
            }
            return false;
        }

        function isUnambiguouslyStartOfFunctionType() {
            nextToken();
            if (token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.DotDotDotToken) {
                // ( )
                // ( ...
                return true;
            }
            if (skipParameterStart()) {
                // We successfully skipped modifiers (if any) and an identifier or binding pattern,
                // now see if we have something that indicates a parameter declaration
                if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken ||
                    token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken) {
                    // ( xxx :
                    // ( xxx ,
                    // ( xxx ?
                    // ( xxx =
                    return true;
                }
                if (token() === SyntaxKind.CloseParenToken) {
                    nextToken();
                    if (token() === SyntaxKind.EqualsGreaterThanToken) {
                        // ( xxx ) =>
                        return true;
                    }
                }
            }
            return false;
        }

        function parseType(): TypeNode {
            return parseTypeWorker();
        }

        function parseTypeWorker(): TypeNode {
            if (isStartOfFunctionType()) {
                return parseFunctionOrConstructorType();
            }
            return parseUnionTypeOrHigher();
        }

        function parseTypeAnnotation(): TypeNode | undefined {
            return parseOptional(SyntaxKind.ColonToken) ? parseType() : undefined;
        }

        // EXPRESSIONS
        function isStartOfLeftHandSideExpression(): boolean {
            switch (token()) {
                case SyntaxKind.ThisKeyword:
                case SyntaxKind.基类关键字_:
                case SyntaxKind.原型关键字_:
                case SyntaxKind.NullKeyword:
                case SyntaxKind.TrueKeyword:
                case SyntaxKind.FalseKeyword:
                case SyntaxKind.NumericLiteral:
                case SyntaxKind.BigIntLiteral:
                case SyntaxKind.StringLiteral:
                case SyntaxKind.字符字面量_:
                case SyntaxKind.NoSubstitutionTemplateLiteral:
                case SyntaxKind.TemplateHead:
                case SyntaxKind.SlashToken:
                case SyntaxKind.SlashEqualsToken:
                case SyntaxKind.对象关键字_:
                case SyntaxKind.结构关键字_:
                case SyntaxKind.NewKeyword:
                case SyntaxKind.OpenParenToken:
                case SyntaxKind.OpenBracketToken:
                case SyntaxKind.OpenBraceToken:
                case SyntaxKind.FunctionKeyword:
                case SyntaxKind.Identifier:                    
                case SyntaxKind.汇编关键字_:
                    return true;
                default:
                    return isIdentifier();
            }
        }

        function isStartOfExpression(): boolean {
            if (isStartOfLeftHandSideExpression()) {
                return true;
            }

            switch (token()) {
                case SyntaxKind.PlusToken:
                case SyntaxKind.MinusToken:
                case SyntaxKind.TildeToken:
                case SyntaxKind.ExclamationToken:
                case SyntaxKind.LessThanToken:
                case SyntaxKind.DotDotDotToken:
                case SyntaxKind.SlashToken:
                case SyntaxKind.SlashEqualsToken:
                case SyntaxKind.NewKeyword:
                case SyntaxKind.NullKeyword:
                case SyntaxKind.TrueKeyword:
                case SyntaxKind.FalseKeyword:
                case SyntaxKind.NumericLiteral:
                case SyntaxKind.StringLiteral:
                case SyntaxKind.字符字面量_:
                case SyntaxKind.NoSubstitutionTemplateLiteral:
                case SyntaxKind.TemplateHead:
                    /*
                case SyntaxKind.指针关键字_:
                case SyntaxKind.正量关键字_:
                case SyntaxKind.整数关键字_:
                case SyntaxKind.小数关键字_:
                case SyntaxKind.正整数关键字_:
                case SyntaxKind.整数8_:
                case SyntaxKind.整数16_:
                case SyntaxKind.整数32_:
                case SyntaxKind.整数64_:
                case SyntaxKind.正整数8_:
                case SyntaxKind.正整数16_:
                case SyntaxKind.正整数32_:
                case SyntaxKind.正整数64_:
                case SyntaxKind.小数32_:
                case SyntaxKind.小数64_:
                case SyntaxKind.虚数32_:
                case SyntaxKind.虚数64_:
                case SyntaxKind.复数64_:
                case SyntaxKind.复数128_:
                case SyntaxKind.字符_:
                case SyntaxKind.字节_:
                    */
                    // Yield/await always starts an expression.  Either it is an identifier (in which case
                    // it is definitely an expression).  Or it's a keyword (either because we're in
                    // a generator or async function, or in strict mode (or both)) and it started a yield or await expression.
                    return true;
                default:
                    // Error tolerance.  If we see the start of some binary operator, we consider
                    // that the start of an expression.  That way we'll parse out a missing identifier,
                    // give a good message about an identifier being missing, and then consume the
                    // rest of the binary expression.
                    if (isBinaryOperator()) {
                        return true;
                    }

                    return isIdentifier();
            }
        }

        function isStartOfExpressionStatement(): boolean {
            // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement.
            return token() !== SyntaxKind.OpenBraceToken &&
                token() !== SyntaxKind.FunctionKeyword &&
                token() !== SyntaxKind.AtToken &&
                isStartOfExpression();
        }

        function parseExpression(): Expression {
            // Expression[in]:
            //      AssignmentExpression[in]
            //      Expression[in] , AssignmentExpression[in]
            let expr = parseAssignmentExpressionOrHigher();
            let operatorToken: BinaryOperatorToken;
            while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) {
                expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher());
            }
            let type: TypeNode | undefined;
            if (token() === SyntaxKind.ColonToken && lookAhead(是简洁变量带类型表达式)) {
                parseExpected(SyntaxKind.ColonToken);
                type = parseType();
                finishNode(type);
            }
            if (parseOptional(SyntaxKind.ColonEqualsToken) || type && parseOptional(SyntaxKind.EqualsToken)) {
                expr = 制作简洁变量声明表达式(expr, parseExpression(), type);
            }
            return expr;
        }

        function 是简洁变量带类型表达式() {
            nextToken();
            return tryParse(parseType) && token() === SyntaxKind.ColonEqualsToken || token() === SyntaxKind.EqualsToken ? true : false;
        }

        function 转换成员(arr: (VariableDeclaration | Expression)[], exp: Expression | Identifier, type?: TypeNode, 转为声明 = false, nodeflags = NodeFlags.None) {
            if (转为声明) {
                const d = <VariableDeclaration>createNode(SyntaxKind.VariableDeclaration, exp.pos);
                d.flags |= nodeflags;
                Debug.assert(exp.kind === SyntaxKind.Identifier);
                d.name = exp as Identifier;
                d.type = type;
                d.end = type ? type.end : exp.end;
                arr.unshift(d);
            }
            else arr.unshift(exp);
        }

        function 转为简洁变量成员数组(arr: (VariableDeclaration | Expression)[], exp: Expression, type?: TypeNode, 转为声明 = false, nodeflags = NodeFlags.None) {
            while (isBinaryExpression(exp)) {
                let { left, right, operatorToken } = exp;
                if (operatorToken.kind === SyntaxKind.CommaToken) {
                    转换成员(arr, right, type, 转为声明, nodeflags);
                }
                else break;
                exp = left;
            }
            转换成员(arr, exp, type, 转为声明, nodeflags);
        }

        function 制作简洁变量声明表达式(left: Expression, right: Expression, type: TypeNode | undefined) {
            const exp = <简洁变量语句_>createNode(SyntaxKind.简洁变量语句_, left.pos);
            exp.flags |= NodeFlags.简洁变量_
            const declarations: VariableDeclaration[] = [];
            const initializers: Expression[] = [];
            转为简洁变量成员数组(declarations, left, type, true, NodeFlags.简洁变量_);
            转为简洁变量成员数组(initializers, right);
            if (declarations.length) exp.declarations = createNodeArray(declarations, left.pos, type ? type.end : left.end);
            if (initializers.length) exp.initializers = createNodeArray(initializers, right.pos, right.end);
            exp.end = right.end;
            return exp;
        }

        function parseInitializer(): Expression | undefined {
            return parseOptional(SyntaxKind.EqualsToken) || parseOptional(SyntaxKind.ColonEqualsToken) ? parseAssignmentExpressionOrHigher() : undefined;
        }

        function parseAssignmentExpressionOrHigher(): Expression {
            // Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized
            // parameter list or is an async arrow function.
            // AsyncArrowFunctionExpression:
            //      1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
            //      2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
            // Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression".
            // And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression".
            //
            // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is
            // not a LeftHandSideExpression, nor does it start a ConditionalExpression.  So we are done
            // with AssignmentExpression if we see one.
            const arrowExpression = tryParseParenthesizedArrowFunctionExpression() || tryParseAsyncSimpleArrowFunctionExpression();
            if (arrowExpression) {
                return arrowExpression;
            }

            // Now try to see if we're in production '1', '2' or '3'.  A conditional expression can
            // start with a LogicalOrExpression, while the assignment productions can only start with
            // LeftHandSideExpressions.
            //
            // So, first, we try to just parse out a BinaryExpression.  If we get something that is a
            // LeftHandSide or higher, then we can try to parse out the assignment expression part.
            // Otherwise, we try to parse out the conditional expression bit.  We want to allow any
            // binary expression here, so we pass in the 'lowest' precedence here so that it matches
            // and consumes anything.
            let expr = parseBinaryExpressionOrHigher(/*precedence*/ 0);

            // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized
            // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single
            // identifier and the current token is an arrow.
            if (expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) {
                return parseSimpleArrowFunctionExpression(<Identifier>expr);
            }

            // Now see if we might be in cases '2' or '3'.
            // If the expression was a LHS expression, and we have an assignment operator, then
            // we're in '2' or '3'. Consume the assignment and return.
            //
            // Note: we call reScanGreaterToken so that we get an appropriately merged token
            // for cases like `> > =` becoming `>>=`
            if ((isLeftHandSideExpression(expr) || 是取值表达式(expr)) && isAssignmentOperator(reScanGreaterToken())) {
                return makeBinaryExpression(expr, parseTokenNode(), parseAssignmentExpressionOrHigher());
            }

            // It wasn't an assignment or a lambda.  This is a conditional expression:
            return parseConditionalExpressionRest(expr);
        }

        function parseSimpleArrowFunctionExpression(identifier: Identifier): ArrowFunction {
            Debug.assert(token() === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>");

            let node: ArrowFunction;
            node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, identifier.pos);

            const parameter = <ParameterDeclaration>createNode(SyntaxKind.Parameter, identifier.pos);
            parameter.name = identifier;
            finishNode(parameter);

            node.parameters = createNodeArray<ParameterDeclaration>([parameter], parameter.pos, parameter.end);

            node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken);
            node.body = parseArrowFunctionExpressionBody();

            return addJSDocComment(finishNode(node));
        }

        function tryParseParenthesizedArrowFunctionExpression(): Expression | undefined {
            const triState = isParenthesizedArrowFunctionExpression();
            if (triState === Tristate.False) {
                // It's definitely not a parenthesized arrow function expression.
                return undefined;
            }

            // If we definitely have an arrow function, then we can just parse one, not requiring a
            // following => or { token. Otherwise, we *might* have an arrow function.  Try to parse
            // it out, but don't allow any ambiguity, and return 'undefined' if this could be an
            // expression instead.
            const arrowFunction = triState === Tristate.True
                ? parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ true)
                : tryParse(parsePossibleParenthesizedArrowFunctionExpressionHead);

            if (!arrowFunction) {
                // Didn't appear to actually be a parenthesized arrow function.  Just bail out.
                return undefined;
            }

            // If we have an arrow, then try to parse the body. Even if not, try to parse if we
            // have an opening brace, just in case we're in an error state.
            const lastToken = token();
            arrowFunction.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken);
            arrowFunction.body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken)
                ? parseArrowFunctionExpressionBody()
                : parseIdentifier();

            return finishNode(arrowFunction);
        }

        //  True        -> We definitely expect a parenthesized arrow function here.
        //  False       -> There *cannot* be a parenthesized arrow function here.
        //  Unknown     -> There *might* be a parenthesized arrow function here.
        //                 Speculatively look ahead to be sure, and rollback if not.
        function isParenthesizedArrowFunctionExpression(): Tristate {
            if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
                return lookAhead(isParenthesizedArrowFunctionExpressionWorker);
            }

            if (token() === SyntaxKind.EqualsGreaterThanToken) {
                // ERROR RECOVERY TWEAK:
                // If we see a standalone => try to parse it as an arrow function expression as that's
                // likely what the user intended to write.
                return Tristate.True;
            }
            // Definitely not a parenthesized arrow function.
            return Tristate.False;
        }

        function isParenthesizedArrowFunctionExpressionWorker() {
            const first = token();
            const second = nextToken();

            if (first === SyntaxKind.OpenParenToken) {
                if (second === SyntaxKind.CloseParenToken) {
                    // Simple cases: "() =>", "(): ", and "() {".
                    // This is an arrow function with no parameters.
                    // The last one is not actually an arrow function,
                    // but this is probably what the user intended.
                    const third = nextToken();
                    switch (third) {
                        case SyntaxKind.EqualsGreaterThanToken:
                        case SyntaxKind.ColonToken:
                        case SyntaxKind.OpenBraceToken:
                            return Tristate.True;
                        default:
                            return Tristate.False;
                    }
                }

                // If encounter "([" or "({", this could be the start of a binding pattern.
                // Examples:
                //      ([ x ]) => { }
                //      ({ x }) => { }
                //      ([ x ])
                //      ({ x })
                if (second === SyntaxKind.OpenBracketToken || second === SyntaxKind.OpenBraceToken) {
                    return Tristate.Unknown;
                }

                // Simple case: "(..."
                // This is an arrow function with a rest parameter.
                if (second === SyntaxKind.DotDotDotToken) {
                    return Tristate.True;
                }

                // If we had "(" followed by something that's not an identifier,
                // then this definitely doesn't look like a lambda.  "this" is not
                // valid, but we want to parse it and then give a semantic error.
                if (!isIdentifier() && second !== SyntaxKind.ThisKeyword && second !== SyntaxKind.原型关键字_) {
                    return Tristate.False;
                }

                switch (nextToken()) {
                    case SyntaxKind.ColonToken:
                        // If we have something like "(a:", then we must have a
                        // type-annotated parameter in an arrow function expression.
                        return Tristate.True;
                    case SyntaxKind.QuestionToken:
                        nextToken();
                        // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda.
                        if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) {
                            return Tristate.True;
                        }
                        // Otherwise it is definitely not a lambda.
                        return Tristate.False;
                    case SyntaxKind.CommaToken:
                    case SyntaxKind.EqualsToken:
                    case SyntaxKind.CloseParenToken:
                        // If we have "(a," or "(a=" or "(a)" this *could* be an arrow function
                        return Tristate.Unknown;
                }
                // It is definitely not an arrow function
                return Tristate.False;
            }
            else {
                Debug.assert(first === SyntaxKind.LessThanToken);

                // If we have "<" not followed by an identifier,
                // then this definitely is not an arrow function.
                if (!isIdentifier()) {
                    return Tristate.False;
                }

                // This *could* be a parenthesized arrow function.
                return Tristate.Unknown;
            }
        }

        function parsePossibleParenthesizedArrowFunctionExpressionHead(): ArrowFunction | undefined {
            const tokenPos = scanner.getTokenPos();
            if (notParenthesizedArrow && notParenthesizedArrow.has(tokenPos.toString())) {
                return undefined;
            }

            const result = parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ false);
            if (!result) {
                (notParenthesizedArrow || (notParenthesizedArrow = createMap())).set(tokenPos.toString(), true);
            }

            return result;
        }

        function tryParseAsyncSimpleArrowFunctionExpression(): ArrowFunction | undefined {
            return undefined;
        }

        function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction | undefined {
            const node = <ArrowFunction>createNodeWithJSDoc(SyntaxKind.ArrowFunction);
            // Arrow functions are never generators.
            //
            // If we're speculatively parsing a signature for a parenthesized arrow function, then
            // we have to have a complete parameter list.  Otherwise we might see something like
            // a => (b => c)
            // And think that "(b =>" was actually a parenthesized arrow function with a missing
            // close paren.
            if (!fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node) && !allowAmbiguity) {
                return undefined;
            }

            // Parsing a signature isn't enough.
            // Parenthesized arrow signatures often look like other valid expressions.
            // For instance:
            //  - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value.
            //  - "(x,y)" is a comma expression parsed as a signature with two parameters.
            //  - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation.
            //  - "a ? (b): function() {}" will too, since function() is a valid JSDoc function type.
            //
            // So we need just a bit of lookahead to ensure that it can only be a signature.
            const hasJSDocFunctionType = node.type && isJSDocFunctionType(node.type);
            if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken)) {
                // Returning undefined here will cause our caller to rewind to where we started from.
                return undefined;
            }

            return node;
        }

        function parseArrowFunctionExpressionBody(): Block | Expression {
            if (token() === SyntaxKind.OpenBraceToken) {
                const 储存的禁止表达式 = 禁止返回表达式;
                禁止返回表达式 = false;
                const ret = parseFunctionBlock(SignatureFlags.None);
                禁止返回表达式 = 储存的禁止表达式;
                return ret;
            }

            if (token() !== SyntaxKind.SemicolonToken &&
                token() !== SyntaxKind.FunctionKeyword &&
                isStartOfStatement() &&
                !isStartOfExpressionStatement()) {
                // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations)
                //
                // Here we try to recover from a potential error situation in the case where the
                // user meant to supply a block. For example, if the user wrote:
                //
                //  a =>
                //      let v = 0;
                //  }
                //
                // they may be missing an open brace.  Check to see if that's the case so we can
                // try to recover better.  If we don't do this, then the next close curly we see may end
                // up preemptively closing the containing construct.
                //
                // Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error.

                const 储存的禁止表达式 = 禁止返回表达式;
                禁止返回表达式 = false;
                const ret = parseFunctionBlock(SignatureFlags.IgnoreMissingOpenBrace | (SignatureFlags.None));
                禁止返回表达式 = 储存的禁止表达式;
                return ret
            }

            return parseAssignmentExpressionOrHigher();
        }

        function parseConditionalExpressionRest(leftOperand: Expression): Expression {
            // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher.
            const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
            if (!questionToken) {
                return leftOperand;
            }

            // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and
            // we do not that for the 'whenFalse' part.
            const node = <ConditionalExpression>createNode(SyntaxKind.ConditionalExpression, leftOperand.pos);
            node.condition = leftOperand;
            node.questionToken = questionToken;
            node.whenTrue = parseAssignmentExpressionOrHigher();
            node.colonToken = parseExpectedToken(SyntaxKind.ColonToken);
            node.whenFalse = nodeIsPresent(node.colonToken)
                ? parseAssignmentExpressionOrHigher()
                : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken));
            return finishNode(node);
        }

        function parseBinaryExpressionOrHigher(precedence: number): Expression {
            const leftOperand = parseUnaryExpressionOrHigher();
            return parseBinaryExpressionRest(precedence, leftOperand);
        }

        function 编译二元运算类型节点(precedence: number): TypeNode {
            const leftOperand = parseType();
            return 编译二元运算类型节点剩余(precedence, leftOperand);
        }

        function 编译二元运算类型节点剩余(precedence: number, leftOperand: TypeNode): TypeNode {
            while (true) {
                reScanGreaterToken();
                const newPrecedence = getBinaryOperatorPrecedence(token());
                const consumeCurrentOperator = newPrecedence > precedence;
                if (!consumeCurrentOperator) {
                    break;
                }
                leftOperand = 制作静态二元类型运算节点(leftOperand, parseTokenNode(), 编译二元运算类型节点(newPrecedence));
            }
            return leftOperand;
        }

        function 制作静态二元类型运算节点(left: TypeNode, operatorToken: BinaryOperatorToken, right: TypeNode): TypeNode {
            const node = <静态二元表达式类型节点_>createNode(SyntaxKind.静态二元表达式类型节点_, left.pos);
            node.left = left;
            node.operatorToken = operatorToken;
            node.right = right;
            return finishNode(node);
        }

        function isInOrOfKeyword(t: SyntaxKind) {
            return t === SyntaxKind.OfKeyword;
        }

        function parseBinaryExpressionRest(precedence: number, leftOperand: Expression): Expression {
            while (true) {
                // We either have a binary operator here, or we're finished.  We call
                // reScanGreaterToken so that we merge token sequences like > and = into >=

                reScanGreaterToken();
                const newPrecedence = getBinaryOperatorPrecedence(token());

                // Check the precedence to see if we should "take" this operator
                // - For left associative operator (all operator but **), consume the operator,
                //   recursively call the function below, and parse binaryExpression as a rightOperand
                //   of the caller if the new precedence of the operator is greater then or equal to the current precedence.
                //   For example:
                //      a - b - c;
                //            ^token; leftOperand = b. Return b to the caller as a rightOperand
                //      a * b - c
                //            ^token; leftOperand = b. Return b to the caller as a rightOperand
                //      a - b * c;
                //            ^token; leftOperand = b. Return b * c to the caller as a rightOperand
                // - For right associative operator (**), consume the operator, recursively call the function
                //   and parse binaryExpression as a rightOperand of the caller if the new precedence of
                //   the operator is strictly grater than the current precedence
                //   For example:
                //      a ** b ** c;
                //             ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand
                //      a - b ** c;
                //            ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand
                //      a ** b - c
                //             ^token; leftOperand = b. Return b to the caller as a rightOperand
                const consumeCurrentOperator = newPrecedence > precedence;

                if (!consumeCurrentOperator) {
                    break;
                }

                leftOperand = makeBinaryExpression(leftOperand, parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence));
            }

            return leftOperand;
        }

        function isBinaryOperator() {
            return getBinaryOperatorPrecedence(token()) > 0;
        }

        function makeBinaryExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression): BinaryExpression {
            const node = <BinaryExpression>createNode(SyntaxKind.BinaryExpression, left.pos);
            node.left = left;
            node.operatorToken = operatorToken;
            node.right = right;
            return finishNode(node);
        }

        function parsePrefixUnaryExpression() {
            const node = <PrefixUnaryExpression>createNode(SyntaxKind.PrefixUnaryExpression);
            node.operator = <PrefixUnaryOperator>token();
            nextToken();
            node.operand = parseSimpleUnaryExpression();

            return finishNode(node);
        }

        /**
         * Parse ES7 exponential expression and await expression
         *
         * ES7 ExponentiationExpression:
         *      1) UnaryExpression[?Yield]
         *      2) UpdateExpression[?Yield] ** ExponentiationExpression[?Yield]
         *
         */
        function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression {
            /**
             * ES7 UpdateExpression:
             *      1) LeftHandSideExpression[?Yield]
             *      2) LeftHandSideExpression[?Yield][no LineTerminator here]++
             *      3) LeftHandSideExpression[?Yield][no LineTerminator here]--
             *      4) ++UnaryExpression[?Yield]
             *      5) --UnaryExpression[?Yield]
             */
            if (isUpdateExpression()) {
                const updateExpression = parseUpdateExpression();
                return updateExpression;
            }

            /**
             * ES7 UnaryExpression:
             *      1) UpdateExpression[?yield]
             *      2) delete UpdateExpression[?yield]
             *      3) void UpdateExpression[?yield]
             *      4) typeof UpdateExpression[?yield]
             *      5) + UpdateExpression[?yield]
             *      6) - UpdateExpression[?yield]
             *      7) ~ UpdateExpression[?yield]
             *      8) ! UpdateExpression[?yield]
             */
            const simpleUnaryExpression = parseSimpleUnaryExpression();
            return simpleUnaryExpression;
        }

        /**
         * Parse ES7 simple-unary expression or higher:
         *
         * ES7 UnaryExpression:
         *      1) UpdateExpression[?yield]
         *      2) delete UnaryExpression[?yield]
         *      3) void UnaryExpression[?yield]
         *      4) typeof UnaryExpression[?yield]
         *      5) + UnaryExpression[?yield]
         *      6) - UnaryExpression[?yield]
         *      7) ~ UnaryExpression[?yield]
         *      8) ! UnaryExpression[?yield]
         *      9) [+Await] await UnaryExpression[?yield]
         */
        function parseSimpleUnaryExpression(): UnaryExpression {
            switch (token()) {
                case SyntaxKind.PlusToken:
                case SyntaxKind.MinusToken:
                case SyntaxKind.TildeToken:
                case SyntaxKind.ExclamationToken:
                    return parsePrefixUnaryExpression();
                default:
                    return parseUpdateExpression();
            }
        }

        /**
         * Check if the current token can possibly be an ES7 increment expression.
         *
         * ES7 UpdateExpression:
         *      LeftHandSideExpression[?Yield]
         *      LeftHandSideExpression[?Yield][no LineTerminator here]++
         *      LeftHandSideExpression[?Yield][no LineTerminator here]--
         *      ++LeftHandSideExpression[?Yield]
         *      --LeftHandSideExpression[?Yield]
         */
        function isUpdateExpression(): boolean {
            // This function is called inside parseUnaryExpression to decide
            // whether to call parseSimpleUnaryExpression or call parseUpdateExpression directly
            switch (token()) {
                case SyntaxKind.PlusToken:
                case SyntaxKind.MinusToken:
                case SyntaxKind.TildeToken:
                case SyntaxKind.ExclamationToken:
                case SyntaxKind.VoidKeyword:
                case SyntaxKind.LessThanToken:
                    return false;
                default:
                    return true;
            }
        }

        /**
         * Parse ES7 UpdateExpression. UpdateExpression is used instead of ES6's PostFixExpression.
         *
         * ES7 UpdateExpression[yield]:
         *      1) LeftHandSideExpression[?yield]
         *      2) LeftHandSideExpression[?yield] [[no LineTerminator here]]++
         *      3) LeftHandSideExpression[?yield] [[no LineTerminator here]]--
         *      4) ++LeftHandSideExpression[?yield]
         *      5) --LeftHandSideExpression[?yield]
         * In TypeScript (2), (3) are parsed as PostfixUnaryExpression. (4), (5) are parsed as PrefixUnaryExpression
         */
        function parseUpdateExpression(): UpdateExpression {
            if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken || token() === SyntaxKind.AmpersandToken || (token() === SyntaxKind.AsteriskToken && !lookAhead(应该是类型转换表达式的类型节点))) {
                let 是取址表达式 = false;
                if (token() === SyntaxKind.AmpersandToken) {
                    setContextFlag(true, NodeFlags.在取址表达式上下文_);
                    是取址表达式 = true;
                }
                const node = <PrefixUnaryExpression>createNode(SyntaxKind.PrefixUnaryExpression);
                node.operator = <PrefixUnaryOperator>token();
                nextToken();
                node.operand = parseLeftHandSideExpressionOrHigher();
                const ret = finishNode(node);
                if (是取址表达式) {
                    setContextFlag(false, NodeFlags.在取址表达式上下文_);
                };
                return ret
            }

            let expression = parseLeftHandSideExpressionOrHigher();

            // Debug.assert(isLeftHandSideExpression(expression));
            if ((token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) {
                const node = <PostfixUnaryExpression>createNode(SyntaxKind.PostfixUnaryExpression, expression.pos);
                node.operand = expression;
                node.operator = <PostfixUnaryOperator>token();
                nextToken();
                return finishNode(node);
            }
            return expression;
        }

        function parseLeftHandSideExpressionOrHigher(): LeftHandSideExpression {
            // Original Ecma:
            // LeftHandSideExpression: See 11.2
            //      NewExpression
            //      CallExpression
            //
            // Our simplification:
            //
            // LeftHandSideExpression: See 11.2
            //      MemberExpression
            //      CallExpression
            //
            // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with
            // MemberExpression to make our lives easier.
            //
            // to best understand the below code, it's important to see how CallExpression expands
            // out into its own productions:
            //
            // CallExpression:
            //      MemberExpression Arguments
            //      CallExpression Arguments
            //      CallExpression[Expression]
            //      CallExpression.IdentifierName
            //      import (AssignmentExpression)
            //      super Arguments
            //      super.IdentifierName
            //
            // Because of the recursion in these calls, we need to bottom out first. There are three
            // bottom out states we can run into: 1) We see 'super' which must start either of
            // the last two CallExpression productions. 2) We see 'import' which must start import call.
            // 3)we have a MemberExpression which either completes the LeftHandSideExpression,
            // or starts the beginning of the first four CallExpression productions.
            let expression: MemberExpression = parseMemberExpressionOrHigher();

            // Now, we *may* be complete.  However, we might have consumed the start of a
            // CallExpression or OptionalExpression.  As such, we need to consume the rest
            // of it here to be complete.
            return parseCallExpressionRest(expression);
        }

        function parseMemberExpressionOrHigher(): MemberExpression {
            // Note: to make our lives simpler, we decompose the NewExpression productions and
            // place ObjectCreationExpression and FunctionExpression into PrimaryExpression.
            // like so:
            //
            //   PrimaryExpression : See 11.1
            //      this
            //      Identifier
            //      Literal
            //      ArrayLiteral
            //      ObjectLiteral
            //      (Expression)
            //      FunctionExpression
            //      new MemberExpression Arguments?
            //
            //   MemberExpression : See 11.2
            //      PrimaryExpression
            //      MemberExpression[Expression]
            //      MemberExpression.IdentifierName
            //
            //   CallExpression : See 11.2
            //      MemberExpression
            //      CallExpression Arguments
            //      CallExpression[Expression]
            //      CallExpression.IdentifierName
            //
            // Technically this is ambiguous.  i.e. CallExpression defines:
            //
            //   CallExpression:
            //      CallExpression Arguments
            //
            // If you see: "new Foo()"
            //
            // Then that could be treated as a single ObjectCreationExpression, or it could be
            // treated as the invocation of "new Foo".  We disambiguate that in code (to match
            // the original grammar) by making sure that if we see an ObjectCreationExpression
            // we always consume arguments if they are there. So we treat "new Foo()" as an
            // object creation only, and not at all as an invocation.  Another way to think
            // about this is that for every "new" that we see, we will consume an argument list if
            // it is there as part of the *associated* object creation node.  Any additional
            // argument lists we see, will become invocation expressions.
            //
            // Because there are no other places in the grammar now that refer to FunctionExpression
            // or ObjectCreationExpression, it is safe to push down into the PrimaryExpression
            // production.
            //
            // Because CallExpression and MemberExpression are left recursive, we need to bottom out
            // of the recursion immediately.  So we parse out a primary expression to start with.
            const expression = parsePrimaryExpression();
            return parseMemberExpressionRest(expression, /*allowOptionalChain*/ true);
        }

        function nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate() {
            nextToken();
            return tokenIsIdentifierOrKeyword(token())
                || token() === SyntaxKind.OpenBracketToken
                || isTemplateStartOfTaggedTemplate();
        }

        function isStartOfOptionalPropertyOrElementAccessChain() {
            return token() === SyntaxKind.QuestionDotToken
                && lookAhead(nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate);
        }

        function parsePropertyAccessExpressionRest(expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {
            const propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
            propertyAccess.expression = expression;
            propertyAccess.questionDotToken = questionDotToken;
            propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
            if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
                propertyAccess.flags |= NodeFlags.OptionalChain;
            }
            return finishNode(propertyAccess);
        }

        function 编译截取表达式(expression: Expression) {
            const 截取表达式 = <截取表达式_>createNode(SyntaxKind.截取表达式_, expression.pos);
            截取表达式.expression = expression;
            if (parseOptional(SyntaxKind.DotDotToken)) {
                if (parseOptional(SyntaxKind.CloseBracketToken)) {
                    return finishNode(截取表达式);
                }
                截取表达式.结束 = parseExpression();
                parseExpected(SyntaxKind.CloseBracketToken);
                return finishNode(截取表达式);
            }
            else {
                截取表达式.开始 = parseExpression();
                parseOptional(SyntaxKind.DotDotToken);
                if (parseOptional(SyntaxKind.CloseBracketToken)) {
                    return finishNode(截取表达式);
                }
                截取表达式.结束 = parseExpression();
                parseExpected(SyntaxKind.CloseBracketToken);
                return finishNode(截取表达式);
            }
        }

        function parseElementAccessExpressionRest(expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {
            const indexedAccess = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression, expression.pos);
            indexedAccess.expression = expression;
            indexedAccess.questionDotToken = questionDotToken;

            if (token() === SyntaxKind.CloseBracketToken) {
                indexedAccess.argumentExpression = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.An_element_access_expression_should_take_an_argument);
            }
            else {
                const argument = parseExpression();
                if (isStringOrNumericLiteralLike(argument)) {
                    argument.text = internIdentifier(argument.text);
                }
                indexedAccess.argumentExpression = argument;
            }

            parseExpected(SyntaxKind.CloseBracketToken);
            if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
                indexedAccess.flags |= NodeFlags.OptionalChain;
            }
            return finishNode(indexedAccess);
        }

        function parseMemberExpressionRest(expression: LeftHandSideExpression, allowOptionalChain: boolean): MemberExpression {
            while (true) {
                let questionDotToken: QuestionDotToken | undefined;
                let isPropertyAccess = false;
                if (allowOptionalChain && isStartOfOptionalPropertyOrElementAccessChain()) {
                    questionDotToken = parseExpectedToken(SyntaxKind.QuestionDotToken);
                    isPropertyAccess = tokenIsIdentifierOrKeyword(token());
                }
                else {
                    isPropertyAccess = parseOptional(SyntaxKind.DotToken);
                }

                if (isPropertyAccess) {
                    expression = parsePropertyAccessExpressionRest(expression, questionDotToken);
                    continue;
                }

                if (!questionDotToken && token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
                    nextToken();
                    const nonNullExpression = <NonNullExpression>createNode(SyntaxKind.NonNullExpression, expression.pos);
                    nonNullExpression.expression = expression;
                    expression = finishNode(nonNullExpression);
                    continue;
                }

                if (parseOptional(SyntaxKind.OpenBracketToken)) {
                    if (questionDotToken === undefined && lookAhead(是截取表达式)) {
                        expression = 编译截取表达式(expression);
                        continue;
                    }
                    expression = parseElementAccessExpressionRest(expression, questionDotToken);
                    continue;
                }
                if (contextFlags & NodeFlags.在取址表达式上下文_) {
                    if (token() === SyntaxKind.LessThanToken) {
                        const 标识符的类型参数 = tryParse(尝试编译标识符的类型参数);
                        if (标识符的类型参数) {
                            if (ts.isIdentifier(expression)) {
                                expression.typeArguments = 标识符的类型参数;
                            }
                            else if (ts.isPropertyAccessExpression(expression)) {
                                expression.name.typeArguments = 标识符的类型参数;
                            }
                        }
                    }
                }
                return <MemberExpression>expression;
            }
        }

        function 是截取表达式() {
            if (parseOptional(SyntaxKind.DotDotToken)) {
                return true;
            }
            const 储存的解析诊断 = parseDiagnostics.length;
            parseExpression();
            if (储存的解析诊断 !== parseDiagnostics.length) {
                return false;
            }
            return parseOptional(SyntaxKind.DotDotToken);
        }

        function isTemplateStartOfTaggedTemplate() {
            return token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead;
        }

        function parseCallExpressionRest(expression: LeftHandSideExpression): LeftHandSideExpression {
            while (true) {
                expression = parseMemberExpressionRest(expression, /*allowOptionalChain*/ true);
                const questionDotToken = parseOptionalToken(SyntaxKind.QuestionDotToken);

                // handle 'foo<<T>()'
                if (token() === SyntaxKind.LessThanToken || token() === SyntaxKind.LessThanLessThanToken) {
                    // See if this is the start of a generic invocation.  If so, consume it and
                    // keep checking for postfix expressions.  Otherwise, it's just a '<' that's
                    // part of an arithmetic expression.  Break out so we consume it higher in the
                    // stack.
                    const typeArguments = tryParse(parseTypeArgumentsInExpression);
                    if (typeArguments) {
                        if (token() === SyntaxKind.OpenParenToken) {
                            const callExpr = <CallExpression>createNode(SyntaxKind.CallExpression, expression.pos);
                            callExpr.expression = expression;
                            callExpr.questionDotToken = questionDotToken;
                            callExpr.typeArguments = typeArguments;
                            callExpr.arguments = parseArgumentList();
                            if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
                                callExpr.flags |= NodeFlags.OptionalChain;
                            }
                            expression = finishNode(callExpr);
                            continue;
                        }
                        else {
                            if(ts.isIdentifier(expression)) {
                                expression.typeArguments = typeArguments;
                                expression.end = typeArguments.end;
                                continue;
                            }
                            else if (ts.isPropertyAccessExpression(expression)) {
                                const name = expression.name;
                                name.typeArguments = typeArguments;
                                name.end = typeArguments.end;
                                expression.end = typeArguments.end;
                                continue;
                            }
                        }
                    }
                }
                else if (token() === SyntaxKind.OpenParenToken) {
                    const callExpr = <CallExpression>createNode(SyntaxKind.CallExpression, expression.pos);
                    callExpr.expression = expression;
                    callExpr.questionDotToken = questionDotToken;
                    callExpr.arguments = parseArgumentList();
                    if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
                        callExpr.flags |= NodeFlags.OptionalChain;
                    }
                    expression = finishNode(callExpr);
                    continue;
                }
                if (questionDotToken) {
                    // We failed to parse anything, so report a missing identifier here.
                    const propertyAccess = createNode(SyntaxKind.PropertyAccessExpression, expression.pos) as PropertyAccessExpression;
                    propertyAccess.expression = expression;
                    propertyAccess.questionDotToken = questionDotToken;
                    propertyAccess.name = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics.Identifier_expected);
                    propertyAccess.flags |= NodeFlags.OptionalChain;
                    expression = finishNode(propertyAccess);
                }
                // 类型转换或类型断言表达式 不允许链式调用
                if (parseOptional(SyntaxKind.点左尖号_)) {
                    if (token() === SyntaxKind.TypeKeyword) {
                        // xxx.xxx.<类型>
                        const exp = <类型查询表达式_>createNode(SyntaxKind.类型查询表达式_, expression.pos);
                        exp.type = parseType();
                        exp.expression = expression;
                        parseExpected(SyntaxKind.GreaterThanToken);
                        expression = finishNode(exp);
                    }
                    else {
                        const exp = <TypeAssertionExpression>createNode(SyntaxKind.TypeAssertionExpression, expression.pos);
                        exp.type = parseType();
                        exp.expression = expression;
                        parseExpected(SyntaxKind.GreaterThanToken);
                        expression = finishNode(exp);
                    }
                }
                break;
            }
            return expression;
        }

        function parseArgumentList() {
            parseExpected(SyntaxKind.OpenParenToken);
            const result = parseDelimitedList(ParsingContext.ArgumentExpressions, parseArgumentExpression);
            parseExpected(SyntaxKind.CloseParenToken);
            return result;
        }

        function 尝试编译标识符的类型参数(){
           const typeArg = 解析标识符类型实参();
           if(typeArg && token() !== SyntaxKind.OpenParenToken) {
               return typeArg;
           }
           return;
        }

        function 解析标识符类型实参() {
            if (reScanLessThanToken() !== SyntaxKind.LessThanToken) {
                return undefined;
            }
            nextToken();

            const typeArguments = parseDelimitedList(ParsingContext.TypeArguments, parseType);
            if (!parseExpected(SyntaxKind.GreaterThanToken)) {
                // If it doesn't have the closing `>` then it's definitely not an type argument list.
                return undefined;
            }

            // If we have a '<', then only parse this as a argument list if the type arguments
            // are complete and we have an open paren.  if we don't, rewind and return nothing.
            return typeArguments;
        }

        function parseTypeArgumentsInExpression() {
            if (reScanLessThanToken() !== SyntaxKind.LessThanToken) {
                return undefined;
            }
            nextToken();

            const typeArguments = parseDelimitedList(ParsingContext.TypeArguments, parseType);
            if (!parseExpected(SyntaxKind.GreaterThanToken)) {
                // If it doesn't have the closing `>` then it's definitely not an type argument list.
                return undefined;
            }

            // If we have a '<', then only parse this as a argument list if the type arguments
            // are complete and we have an open paren.  if we don't, rewind and return nothing.
            return typeArguments && canFollowTypeArgumentsInExpression()
                ? typeArguments
                : undefined;
        }

        function canFollowTypeArgumentsInExpression(): boolean {
            switch (token()) {
                case SyntaxKind.OpenParenToken:                 // foo<x>(
                case SyntaxKind.NoSubstitutionTemplateLiteral:  // foo<T> `...`
                case SyntaxKind.TemplateHead:                   // foo<T> `...${100}...`
                // these are the only tokens can legally follow a type argument
                // list. So we definitely want to treat them as type arg lists.
                // falls through
                case SyntaxKind.DotToken:                       // foo<x>.
                case SyntaxKind.CloseParenToken:                // foo<x>)
                case SyntaxKind.CloseBracketToken:              // foo<x>]
                case SyntaxKind.ColonToken:                     // foo<x>:
                case SyntaxKind.SemicolonToken:                 // foo<x>;
                case SyntaxKind.QuestionToken:                  // foo<x>?
                case SyntaxKind.EqualsEqualsToken:              // foo<x> ==
                case SyntaxKind.ExclamationEqualsToken:         // foo<x> !=

                case SyntaxKind.AmpersandAmpersandToken:        // foo<x> &&
                case SyntaxKind.BarBarToken:                    // foo<x> ||
                case SyntaxKind.CaretToken:                     // foo<x> ^
                case SyntaxKind.AmpersandToken:                 // foo<x> &
                case SyntaxKind.BarToken:                       // foo<x> |
                case SyntaxKind.CloseBraceToken:                // foo<x> }
                case SyntaxKind.EndOfFileToken:                 // foo<x>
                case SyntaxKind.Identifier:
                    // these cases can't legally follow a type arg list.  However, they're not legal
                    // expressions either.  The user is probably in the middle of a generic type. So
                    // treat it as such.
                    return true;

                case SyntaxKind.CommaToken:                     // foo<x>,
                case SyntaxKind.OpenBraceToken:                 // foo<x> {
                // We don't want to treat these as type arguments.  Otherwise we'll parse this
                // as an invocation expression.  Instead, we want to parse out the expression
                // in isolation from the type arguments.
                // falls through
                default:
                    // Anything else treat as an expression.
                    return false;
            }
        }

        function 尝试解析字面量类型头部类型节点() {
            if (inContext(NodeFlags.在继承条款上下文_)) return undefined;
            const 储存的解析诊断 = parseDiagnostics.length;
            const tn = parseType();
            const tok = token();
            if (储存的解析诊断 === parseDiagnostics.length && (tok === SyntaxKind.点左括号_ || tok === SyntaxKind.OpenBraceToken)) {
                return tn;
            }
            return undefined;
        }

        function 解析词典字面量元素() {
            if (token() === SyntaxKind.DotDotDotToken) {
                return parseSpreadElement() as SpreadElement;
            }
            let n = <词典键值表达式_>createNode(SyntaxKind.词典键值表达式_);
            n.键表达式 = parseAssignmentExpressionOrHigher();
            parseExpected(SyntaxKind.ColonToken);
            n.值表达式 = parseAssignmentExpressionOrHigher();
            return finishNode(n);
        }

        function 解析非JSON数组字面量成员(): NodeArray<Expression> {
            return parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement);
        }

        enum 字面量类型头_{
            No = 0,
            动态数组_,
            数组类型_,
            词典类型_,
            对象类型_,
        }

        function 判断字面量类型头(n: Node | undefined): 字面量类型头_ {
            if (!n) return 字面量类型头_.No;
            if (是动态数组类型节点(n)) {
                return 字面量类型头_.动态数组_;
            }
            if (是数组类型节点(n)) {
                return 字面量类型头_.数组类型_;
            }
            if (是词典类型节点(n)) {
                return 字面量类型头_.词典类型_;
            }
            if (isExpressionWithTypeArguments(n) || isTypeReferenceNode(n)) {
                return 字面量类型头_.对象类型_;
            }
            if (isParenthesizedTypeNode(n) || 是类型限定符类型节点(n)) {
                n = n.type;
                return 判断字面量类型头(n);
            }
            return 字面量类型头_.No;
        }

        function 是数组类型节点(n: Node): n is ArrayTypeNode {
            return !!(n.kind === SyntaxKind.ArrayType);
        }

        function 是动态数组类型节点(n: Node): n is 动态数组类型节点_ {
            return !!(n.kind === SyntaxKind.动态数组_);
        }

        function 是词典类型节点(n: Node): n is 词典类型节点_ {
            return !!(n.kind === SyntaxKind.词典类型_);
        }

        function parsePrimaryExpression(): PrimaryExpression {
            if (!(contextFlags & NodeFlags.JsonFile)) {
                const tn = tryParse(尝试解析字面量类型头部类型节点);
                if (tn && parseOptional(SyntaxKind.OpenBraceToken)) {
                    const 表达式 = <ObjectLiteralExpression | ArrayLiteralExpression | 动态数组表达式_ | 词典字面量表达式_>createNodeWithJSDoc(SyntaxKind.Unknown, tn.pos)
                    if (scanner.hasPrecedingLineBreak()) {
                        表达式.multiLine = true;
                    }
                    if (判断字面量类型头(tn) === 字面量类型头_.数组类型_) {
                        表达式.kind = SyntaxKind.ArrayLiteralExpression;
                        表达式.type = tn;
                        (<ArrayLiteralExpression>表达式).elements = 解析非JSON数组字面量成员();
                        parseExpected(SyntaxKind.CloseBraceToken);
                        return finishNode(表达式)
                    }
                    if (判断字面量类型头(tn) === 字面量类型头_.动态数组_) {
                        表达式.kind = SyntaxKind.动态数组表达式_;
                        表达式.type = tn;
                        (<动态数组表达式_>表达式).elements = 解析非JSON数组字面量成员();
                        parseExpected(SyntaxKind.CloseBraceToken);
                        return finishNode(表达式);
                    }
                    if (判断字面量类型头(tn) === 字面量类型头_.词典类型_) {
                        表达式.kind = SyntaxKind.词典字面量表达式_;
                        表达式.type = tn;
                        (<词典字面量表达式_>表达式).elements = parseDelimitedList(ParsingContext.ObjectLiteralMembers, 解析词典字面量元素);
                        parseExpected(SyntaxKind.CloseBraceToken);
                        return finishNode(表达式);
                    }
                    if (判断字面量类型头(tn) === 字面量类型头_.对象类型_) {
                        表达式.kind = SyntaxKind.ObjectLiteralExpression;
                        表达式.type = tn;
                        (<ObjectLiteralExpression>表达式).properties = 解析非JSON结构属性();
                        parseExpected(SyntaxKind.CloseBraceToken);
                        return finishNode(表达式);
                    }
                    表达式.type = tn;
                    parseErrorAt(tn.pos, tn.end, Diagnostics.不是有效的字面量表达式的注释类型);
                    return finishNode(表达式);
                }
                if (tn && parseOptional(SyntaxKind.点左括号_)) {
                    const 表达式 = <类型转换表达式_>createNodeWithJSDoc(SyntaxKind.类型转换表达式_, tn.pos);
                    表达式.type = tn;
                    表达式.expression = parseExpression();
                    parseExpected(SyntaxKind.CloseParenToken);
                    return finishNode(表达式);
                }

            }
            switch (token()) {
                case SyntaxKind.NumericLiteral:
                case SyntaxKind.StringLiteral:
                case SyntaxKind.NoSubstitutionTemplateLiteral:
                case SyntaxKind.BigIntLiteral:
                case SyntaxKind.字符字面量_:
                    return parseLiteralNode();
                case SyntaxKind.原型关键字_:
                    return parseIdentifierName(Diagnostics.Expression_expected)
                case SyntaxKind.ThisKeyword:
                case SyntaxKind.NullKeyword:
                case SyntaxKind.TrueKeyword:
                case SyntaxKind.FalseKeyword:
                    return parseTokenNode<PrimaryExpression>();
                case SyntaxKind.OpenParenToken:
                    return parseParenthesizedExpression();
                case SyntaxKind.OpenBracketToken:
                    return parseArrayLiteralExpression();
                case SyntaxKind.OpenBraceToken:
                    return contextFlags & NodeFlags.JsonFile ? parseObjectLiteralExpression() : 解析词典或动态数组表达式();
                case SyntaxKind.FunctionKeyword:
                    return parseFunctionExpression();
                case SyntaxKind.NewKeyword:
                    return parseNewExpressionOrNewDotTarget();
                case SyntaxKind.SlashToken:
                case SyntaxKind.SlashEqualsToken:
                    if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) {
                        return parseLiteralNode();
                    }
                    break;
                case SyntaxKind.TemplateHead:
                    return parseTemplateExpression();
            }
            return parseIdentifier(Diagnostics.Expression_expected);
        }

        function parseParenthesizedExpression(): ParenthesizedExpression {
            const node = <ParenthesizedExpression>createNodeWithJSDoc(SyntaxKind.ParenthesizedExpression);
            parseExpected(SyntaxKind.OpenParenToken);
            node.expression = parseExpression();
            parseExpected(SyntaxKind.CloseParenToken);
            return finishNode(node);
        }

        function parseSpreadElement(): Expression {
            const node = <SpreadElement>createNode(SyntaxKind.SpreadElement);
            parseExpected(SyntaxKind.DotDotDotToken);
            node.expression = parseAssignmentExpressionOrHigher();
            return finishNode(node);
        }

        function parseArgumentOrArrayLiteralElement(): Expression {
            return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() :
                token() === SyntaxKind.CommaToken ? <Expression>createNode(SyntaxKind.OmittedExpression) :
                    parseAssignmentExpressionOrHigher();
        }

        function parseArgumentExpression(): Expression {
            return parseArgumentOrArrayLiteralElement();
        }

        function parseArrayLiteralExpression(): ArrayLiteralExpression {
            const node = <ArrayLiteralExpression>createNode(SyntaxKind.ArrayLiteralExpression);
            parseExpected(SyntaxKind.OpenBracketToken);
            if (scanner.hasPrecedingLineBreak()) {
                node.multiLine = true;
            }
            node.elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement);
            parseExpected(SyntaxKind.CloseBracketToken);
            return finishNode(node);
        }

        function 解析初始化成员(): PropertyAssignment | Expression {
            const expr = parseArgumentExpression();
            if (token() === SyntaxKind.ColonToken && ts.isIdentifier(expr)) {
                const node = <PropertyAssignment>createNodeWithJSDoc(SyntaxKind.PropertyAssignment, expr.pos);
                node.name = expr;
                parseExpected(SyntaxKind.ColonToken);
                node.initializer = parseArgumentExpression();
                return finishNode(node);
            }
            else {
                return expr;
            }
        }

        function parseObjectLiteralElement(): ObjectLiteralElementLike {
            const node = <ObjectLiteralElementLike>createNodeWithJSDoc(SyntaxKind.Unknown);
            const tokenIsIdentifier = isIdentifier();
            node.name = parsePropertyName();
            // check if it is short-hand property assignment or normal property assignment
            // NOTE: if token is EqualsToken it is interpreted as CoverInitializedName production
            // CoverInitializedName[Yield] :
            //     IdentifierReference[?Yield] Initializer[In, ?Yield]
            // this is necessary because ObjectLiteral productions are also used to cover grammar for ObjectAssignmentPattern
            const isShorthandPropertyAssignment = tokenIsIdentifier && (token() !== SyntaxKind.ColonToken);
            if (isShorthandPropertyAssignment) {
                node.kind = SyntaxKind.ShorthandPropertyAssignment;
                const equalsToken = parseOptionalToken(SyntaxKind.EqualsToken);
                if (equalsToken) {
                    (<ShorthandPropertyAssignment>node).equalsToken = equalsToken;
                    (<ShorthandPropertyAssignment>node).objectAssignmentInitializer = parseAssignmentExpressionOrHigher();
                }
            }
            else {
                node.kind = SyntaxKind.PropertyAssignment;
                parseExpected(SyntaxKind.ColonToken);
                (<PropertyAssignment>node).initializer = parseAssignmentExpressionOrHigher();
            }
            return finishNode(node);
        }

        function 解析非JSON结构属性(): NodeArray<ObjectLiteralElementLike> {
            return parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true);
        }

        function 解析词典或动态数组表达式(): 词典字面量表达式_ | 动态数组表达式_ {
            const node = <词典字面量表达式_ | 动态数组表达式_>createNode(SyntaxKind.动态数组表达式_);
            parseExpected(SyntaxKind.OpenBraceToken);
            let 是词典 = false;
            if (lookAhead(是词典字面量表达式)) {
                node.kind = SyntaxKind.词典字面量表达式_;
                是词典 = true
            }
            if (scanner.hasPrecedingLineBreak()) {
                node.multiLine = true;
            }
            node.elements = 是词典 ? parseDelimitedList(ParsingContext.ObjectLiteralMembers, 解析词典字面量元素) : parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement);
            parseExpected(SyntaxKind.CloseBraceToken);
            return finishNode(node);
        }

        function 是词典字面量表达式() {
            let isSp = parseArgumentOrArrayLiteralElement();
            while (isSpreadElement(isSp) || isOmittedExpression(isSp)) {
                if (!parseOptional(SyntaxKind.CommaToken)) {
                    break;
                }
                isSp = parseArgumentOrArrayLiteralElement();
            }
            if (token() === SyntaxKind.ColonToken) {
                return true;
            }
            return false
        }

        function parseObjectLiteralExpression(): ObjectLiteralExpression {
            const node = <ObjectLiteralExpression>createNode(SyntaxKind.ObjectLiteralExpression);
            parseExpected(SyntaxKind.OpenBraceToken);
            if (scanner.hasPrecedingLineBreak()) {
                node.multiLine = true;
            }

            node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true);
            parseExpected(SyntaxKind.CloseBraceToken);
            return finishNode(node);
        }

        function parseFunctionExpression(): FunctionExpression {
            // GeneratorExpression:
            //      function* BindingIdentifier [Yield][opt](FormalParameters[Yield]){ GeneratorBody }
            //
            // FunctionExpression:
            //      function BindingIdentifier[opt](FormalParameters){ FunctionBody }

            const node = <FunctionExpression>createNodeWithJSDoc(SyntaxKind.FunctionExpression);
            parseExpected(SyntaxKind.FunctionKeyword);
            node.name = parseOptionalIdentifier();
            fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
            const 储存的禁止表达式 = 禁止返回表达式;
            禁止返回表达式 = false;
            node.body = parseFunctionBlock(0);
            禁止返回表达式 = 储存的禁止表达式;
            return finishNode(node);
        }

        function parseOptionalIdentifier(): Identifier | undefined {
            return isIdentifier() ? parseIdentifier() : undefined;
        }

        function parseNewExpressionOrNewDotTarget(): NewExpression {
            const node = <NewExpression>createNode(SyntaxKind.NewExpression);
            parseExpected(SyntaxKind.NewKeyword);
            node.type = parseType();
            const 有初始 = parseOptional(SyntaxKind.OpenParenToken);
            if (有初始) {
                node.initExpression = parseDelimitedList(ParsingContext.初始化成员_, 解析初始化成员);
                parseExpected(SyntaxKind.CloseParenToken);
            }
            return finishNode(node);
        }

        // STATEMENTS
        function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block {
            const node = <Block>createNode(SyntaxKind.Block);
            if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) {
                if (scanner.hasPrecedingLineBreak()) {
                    node.multiLine = true;
                }
                node.statements = parseList(ParsingContext.BlockStatements, 解析语句);
                parseExpected(SyntaxKind.CloseBraceToken);
            }
            else {
                node.statements = createMissingList<Statement>();
            }
            return finishNode(node);
        }

        function 解析版本语句块(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage, 在顶级: boolean = false): Block {
            const node = <Block>createNode(SyntaxKind.Block);
            if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) {
                if (scanner.hasPrecedingLineBreak()) {
                    node.multiLine = true;
                }
                node.statements = parseList(在顶级? ParsingContext.源码顶级语句_ : ParsingContext.BlockStatements, 在顶级? 解析源码顶级语句 : 解析语句);
                parseExpected(SyntaxKind.CloseBraceToken);
            }
            else {
                node.statements = createMissingList<Statement>();
            }
            return finishNode(node);
        }

        function parseFunctionBlock(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block {
            const block = parseBlock(!!(flags & SignatureFlags.IgnoreMissingOpenBrace), diagnosticMessage);
            return block;
        }

        function parseEmptyStatement(): Statement {
            const node = <Statement>createNode(SyntaxKind.EmptyStatement);
            parseExpected(SyntaxKind.SemicolonToken);
            return finishNode(node);
        }

        function parseIfStatement(syn: SyntaxKind): IfStatement {
            const node = <IfStatement>createNode(SyntaxKind.IfStatement);
            parseExpected(syn);
            parseExpected(SyntaxKind.OpenParenToken);
            node.expression = parseExpression();
            parseExpected(SyntaxKind.CloseParenToken);
            node.thenStatement = 解析语句();
            if (parseOptional(SyntaxKind.ElseKeyword) || token() === SyntaxKind.另如关键字_) {
                node.elseStatement = 解析语句();
            }
            return finishNode(node);
        }

        function 解析基类调用(): ExpressionStatement {
            const exst = <ExpressionStatement>createNodeWithJSDoc(SyntaxKind.ExpressionStatement);
            const node = <CallExpression>createNode(SyntaxKind.CallExpression);
            node.expression = parseIdentifierName();
            node.arguments = parseArgumentList();
            if (!允许基类调用) {
                parseErrorAt(node.expression.pos, node.expression.end, Diagnostics.禁止访问基类);
            }
            finishNode(node);
            node.flags |= NodeFlags.是基类调用_;
            exst.expression = node;
            finishNode(exst);
            parseSemicolon();
            return exst;
        }

        function 解析源码级版本语句(node?: 版本语句_): 版本语句_ {
            if (!node) node = <版本语句_>createNodeWithJSDoc(SyntaxKind.Unknown);
            const 储存的上下文 = contextFlags;
            setContextFlag(true, NodeFlags.在版本验证上下文_);
            node.kind = SyntaxKind.版本语句_;
            (<版本语句_>node).是顶级的 = true;
            parseExpected(SyntaxKind.版本关键字_);
            parseExpected(SyntaxKind.OpenParenToken);
            node.expression = parseIdentifier();
            const id = node.expression.escapedText;
            if (!文件内使用的版本标识符组.has(id)) {
                文件内使用的版本标识符组.add(id);
            }
            parseExpected(SyntaxKind.CloseParenToken);
            (<版本语句_>node).thenStatement = 解析版本语句块(false, undefined, true);
            (<版本语句_>node).thenStatement.版本容器块种类 = 是版本另如容器块 ? 版本容器块种类_.是版本另如容器块_ : 版本容器块种类_.是版本容器块_;
            是版本另如容器块 = false;
            if (parseOptional(SyntaxKind.ElseKeyword)) {
                if (token() === SyntaxKind.版本关键字_) {
                    是版本另如容器块 = true;
                    (<版本语句_>node).elseStatement = 解析源码顶级语句();
                }
                else {
                    (<版本语句_>node).elseStatement = 解析版本语句块(false, undefined, true);
                    (<Block>(<版本语句_>node).elseStatement).版本容器块种类 = 版本容器块种类_.是版本否则容器块_;
                }
            }
            const ret = finishNode(node);
            setContextFlag(false, NodeFlags.在版本验证上下文_);
            contextFlags = 储存的上下文;
            return ret;
        }


        function 解析版本语句(node?: 版本语句_ | 版本表达式语句_ , 在顶级: boolean = false): 版本语句_ | 版本表达式语句_ {
            if (!node) node = <版本语句_ | 版本表达式语句_>createNodeWithJSDoc(SyntaxKind.Unknown);
            parseExpected(SyntaxKind.版本关键字_);
            if (parseOptional(SyntaxKind.EqualsToken)) {
                node.kind = SyntaxKind.版本表达式语句_;
                (<版本表达式语句_>node).expression = parseIdentifier();
                const id = (<版本表达式语句_>node).expression.escapedText;
                if(!文件内使用的版本标识符组.has(id)){
                    文件内使用的版本标识符组.add(id);
                }
                if (!在顶级) parseErrorAt(node.pos, node.expression.end, Diagnostics.版本声明不能位于_语句级版本_块内);
                const ret =  finishNode(node);
                parseSemicolon();
                return ret;
            }
            else {
                const 储存的上下文 = contextFlags;
                setContextFlag(true, NodeFlags.在版本验证上下文_);
                node.kind = SyntaxKind.版本语句_;
                (<版本语句_>node).是顶级的 = 在顶级;
                parseExpected(SyntaxKind.OpenParenToken);
                node.expression = parseIdentifier();
                const id = node.expression.escapedText;
                if (!文件内使用的版本标识符组.has(id)) {
                    文件内使用的版本标识符组.add(id);
                }
                parseExpected(SyntaxKind.CloseParenToken);
                (<版本语句_>node).thenStatement = 解析版本语句块(false, undefined, 在顶级);
                (<版本语句_>node).thenStatement.版本容器块种类 = 是版本另如容器块 ? 版本容器块种类_.是版本另如容器块_ : 版本容器块种类_.是版本容器块_;
                是版本另如容器块 = false;
                if (parseOptional(SyntaxKind.ElseKeyword)) {
                    if (token() === SyntaxKind.版本关键字_) {
                        是版本另如容器块 = true;
                        (<版本语句_>node).elseStatement = 在顶级 ? 解析程序集顶级语句() : 解析语句();
                    }
                    else {
                        (<版本语句_>node).elseStatement = 解析版本语句块(false, undefined, 在顶级);
                        (<Block>(<版本语句_>node).elseStatement).版本容器块种类 = 版本容器块种类_.是版本否则容器块_;
                    }
                }
                const ret = finishNode(node);
                setContextFlag(false, NodeFlags.在版本验证上下文_);
                contextFlags = 储存的上下文;
                return ret;
            }
        }

        function parseForOrForOfStatement(): Statement {
            const pos = getNodePos();
            setContextFlag(true, NodeFlags.在循环语句上下文_);
            parseExpected(SyntaxKind.ForKeyword);
            parseExpected(SyntaxKind.OpenParenToken);
            let forOrForOfStatement: IterationStatement;
            if (!parseOptional(SyntaxKind.CloseParenToken)) {
                let initializer!: VariableDeclarationList | Expression;
                if (token() !== SyntaxKind.SemicolonToken) {
                    if (token() === SyntaxKind.LetKeyword || token() === SyntaxKind.ConstKeyword || lookAhead(前方有属于关键字)) {
                        initializer = parseVariableDeclarationList(/*inForStatementInitializer*/ true);
                    }
                    else {
                        const 可能是简洁变量 = parseExpression();
                        initializer = 是简洁变量语句(可能是简洁变量) ? 转换简洁变量语句为类型声明列表(可能是简洁变量) : 可能是简洁变量;
                    }
                }
                if (parseOptional(SyntaxKind.OfKeyword)) {
                    const forOfStatement = <ForOfStatement>createNode(SyntaxKind.ForOfStatement, pos);
                    forOfStatement.initializer = initializer
                    forOfStatement.initializer.flags |= NodeFlags.Let;
                    forOfStatement.expression = parseAssignmentExpressionOrHigher();
                    parseExpected(SyntaxKind.CloseParenToken);
                    forOrForOfStatement = forOfStatement;
                }
                else {
                    const forStatement = <ForStatement | WhileStatement>createNode(SyntaxKind.Unknown, pos);
                    if (parseOptional(SyntaxKind.SemicolonToken)) {
                        (<ForStatement>forStatement).kind = SyntaxKind.ForStatement;
                        (<ForStatement>forStatement).initializer = initializer;
                        if (token() !== SyntaxKind.SemicolonToken && token() !== SyntaxKind.CloseParenToken) {
                            (<ForStatement>forStatement).condition = parseExpression();
                        }
                        parseExpected(SyntaxKind.SemicolonToken);
                        if (token() !== SyntaxKind.CloseParenToken) {
                            (<ForStatement>forStatement).incrementor = parseExpression();
                        }
                    }
                    else if (ts.isExpression(initializer)) {
                        (<WhileStatement>forStatement).kind = SyntaxKind.WhileStatement;
                        (<WhileStatement>forStatement).expression = initializer
                    }
                    parseExpected(SyntaxKind.CloseParenToken);
                    forOrForOfStatement = forStatement;
                }
            }
            else {
                const forOfStatement = <ForStatement>createNode(SyntaxKind.ForStatement, pos);
                forOrForOfStatement = forOfStatement;
            }
            forOrForOfStatement.statement = 解析语句();
            const forSta = finishNode(forOrForOfStatement);
            setContextFlag(false, NodeFlags.在循环语句上下文_);
            return forSta;
        }

        function parseBreakOrContinueStatement(kind: SyntaxKind): BreakOrContinueStatement {
            const node = <BreakOrContinueStatement>createNode(kind);

            parseExpected(kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword);
            if (!canParseSemicolon()) {
                node.label = parseIdentifier();
            }
            parseSemicolon();
            return finishNode(node);
        }

        function parseReturnStatement(): ReturnStatement {
            const node = <ReturnStatement>createNode(SyntaxKind.ReturnStatement);

            parseExpected(SyntaxKind.ReturnKeyword);
            if (!canParseSemicolon()) {
                node.expression = parseExpression();
                if (禁止返回表达式) parseErrorAtPosition(node.expression.pos, node.expression.end, Diagnostics.构建声明或释放声明禁止返回值);
            }

            parseSemicolon();
            return finishNode(node);
        }

        function parseCaseClause(): CaseClause {
            const node = <CaseClause>createNode(SyntaxKind.CaseClause);
            parseExpected(SyntaxKind.CaseKeyword);
            node.expression = inContext(NodeFlags.类型查询上下文_) ? parseType() : parseExpression();
            parseExpected(SyntaxKind.ColonToken);
            node.statements = parseList(ParsingContext.SwitchClauseStatements, 解析语句);
            return finishNode(node);
        }

        function parseDefaultClause(): DefaultClause {
            const node = <DefaultClause>createNode(SyntaxKind.DefaultClause);
            parseExpected(SyntaxKind.DefaultKeyword);
            parseExpected(SyntaxKind.ColonToken);
            node.statements = parseList(ParsingContext.SwitchClauseStatements, 解析语句);
            return finishNode(node);
        }

        function parseCaseOrDefaultClause(): CaseOrDefaultClause {
            return token() === SyntaxKind.CaseKeyword ? parseCaseClause() : parseDefaultClause();
        }

        function parseSwitchStatement(): SwitchStatement {
            setContextFlag(true, NodeFlags.在假如语句上下文_)
            const node = <SwitchStatement>createNode(SyntaxKind.SwitchStatement);
            parseExpected(SyntaxKind.SwitchKeyword);
            parseExpected(SyntaxKind.OpenParenToken);
            node.expression = parseExpression();
            parseExpected(SyntaxKind.CloseParenToken);
            const caseBlock = <CaseBlock>createNode(SyntaxKind.CaseBlock);
            parseExpected(SyntaxKind.OpenBraceToken);
            if (是类型查询表达式(node.expression)) setContextFlag(true, NodeFlags.类型查询上下文_);
            caseBlock.clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause);
            if (是类型查询表达式(node.expression)) setContextFlag(false, NodeFlags.类型查询上下文_);
            parseExpected(SyntaxKind.CloseBraceToken);
            node.caseBlock = finishNode(caseBlock);
            const switchSta = finishNode(node);
            setContextFlag(false, NodeFlags.在假如语句上下文_);
            return switchSta;
        }


        function parseThrowStatement(): ThrowStatement {
            // ThrowStatement[Yield] :
            //      throw [no LineTerminator here]Expression[In, ?Yield];

            // Because of automatic semicolon insertion, we need to report error if this
            // throw could be terminated with a semicolon.  Note: we can't call 'parseExpression'
            // directly as that might consume an expression on the following line.
            // We just return 'undefined' in that case.  The actual error will be reported in the
            // grammar walker.
            const node = <ThrowStatement>createNode(SyntaxKind.ThrowStatement);
            parseExpected(SyntaxKind.ThrowKeyword);
            node.expression = scanner.hasPrecedingLineBreak() ? undefined : parseExpression();
            parseSemicolon();
            return finishNode(node);
        }

        function 解析断言语句(node?: 断言语句_): 断言语句_ {
            // ThrowStatement[Yield] :
            //      throw [no LineTerminator here]Expression[In, ?Yield];

            // Because of automatic semicolon insertion, we need to report error if this
            // throw could be terminated with a semicolon.  Note: we can't call 'parseExpression'
            // directly as that might consume an expression on the following line.
            // We just return 'undefined' in that case.  The actual error will be reported in the
            // grammar walker.
            if (!node) {
                node = <断言语句_>createNode(SyntaxKind.断言语句_);
            }
            else node.kind = SyntaxKind.断言语句_;
            parseExpected(SyntaxKind.断言关键字_);
            node.arguments = parseArgumentList();
            parseOptionalToken(SyntaxKind.SemicolonToken);
            return finishNode(node);
        }

        // TODO: Review for error recovery
        function parseTryStatement(): TryStatement {
            const node = <TryStatement>createNode(SyntaxKind.TryStatement);

            parseExpected(SyntaxKind.TryKeyword);
            node.tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false);
            node.catchClause = token() === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined;

            // If we don't have a catch clause, then we must have a finally clause.  Try to parse
            // one out no matter what.
            if (!node.catchClause || token() === SyntaxKind.FinallyKeyword) {
                parseExpected(SyntaxKind.FinallyKeyword);
                node.finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false);
            }

            return finishNode(node);
        }

        function parseCatchClause(): CatchClause {
            const result = <CatchClause>createNode(SyntaxKind.CatchClause);
            parseExpected(SyntaxKind.CatchKeyword);

            if (parseOptional(SyntaxKind.OpenParenToken)) {
                result.variableDeclaration = parseVariableDeclaration();
                parseExpected(SyntaxKind.CloseParenToken);
            }
            else {
                // Keep shape of node to avoid degrading performance.
                result.variableDeclaration = undefined;
            }

            result.block = parseBlock(/*ignoreMissingOpenBrace*/ false);
            return finishNode(result);
        }

        function parseDebuggerStatement(): Statement {
            const node = <Statement>createNode(SyntaxKind.DebuggerStatement);
            parseExpected(SyntaxKind.DebuggerKeyword);
            parseSemicolon();
            return finishNode(node);
        }

        function parseExpressionOrLabeledStatement(): ExpressionStatement | LabeledStatement {
            // Avoiding having to do the lookahead for a labeled statement by just trying to parse
            // out an expression, seeing if it is identifier and then seeing if it is followed by
            // a colon.
            const node = <ExpressionStatement | LabeledStatement>createNodeWithJSDoc(SyntaxKind.Unknown);
            const expression = parseExpression();
            if (expression.kind === SyntaxKind.Identifier && parseOptional(SyntaxKind.ColonToken)) {
                node.kind = SyntaxKind.LabeledStatement;
                (<LabeledStatement>node).label = <Identifier>expression;
                (<LabeledStatement>node).statement = 解析语句();
            }
            else if (是简洁变量语句(expression)) {
                for (let i = 0; i < expression.initializers.length; i++) {
                    let intit = expression.initializers[i];
                    expression.declarations[i].initializer = intit;
                    expression.declarations[i].end = intit.end;
                    expression.declarations.end = intit.end;
                }
                const sta = <VariableStatement>createNode(SyntaxKind.VariableStatement, expression.pos);
                sta.declarationList = <VariableDeclarationList>createNode(SyntaxKind.VariableDeclarationList, expression.pos);
                sta.declarationList.flags |= NodeFlags.Let | expression.flags;
                sta.declarationList.declarations = expression.declarations;
                sta.declarationList.end = expression.end;
                parseSemicolon();
                return finishNode(sta) as Statement as ExpressionStatement;
            }
            else {
                node.kind = SyntaxKind.ExpressionStatement;
                (<ExpressionStatement>node).expression = expression;
                parseSemicolon();
            }
            return finishNode(node);
        }

        function nextTokenIsIdentifierOrKeywordOnSameLine() {
            nextToken();
            return tokenIsIdentifierOrKeyword(token()) && !scanner.hasPrecedingLineBreak();
        }

        function 是源码顶级语句开始(): boolean {
            switch (token()) {
                case SyntaxKind.ImportKeyword:
                case SyntaxKind.程序关键字_:                    
                case SyntaxKind.输出转换词典头_:
                case SyntaxKind.输入转换词典头_:
                case SyntaxKind.版本关键字_:
                    return true;
                default:
                    return false;
            }
        }

        function 是程序集顶级语句(): boolean {
            switch (token()) {
                case SyntaxKind.版本关键字_:
                case SyntaxKind.ElseKeyword:
                case SyntaxKind.TypeKeyword:
                case SyntaxKind.LetKeyword:
                case SyntaxKind.共享关键字_:
                case SyntaxKind.ConstKeyword:
                case SyntaxKind.FunctionKeyword:
                case SyntaxKind.方法关键字_:
                case SyntaxKind.启动关键字_:
                case SyntaxKind.初始关键字_:
                case SyntaxKind.EnumKeyword:
                case SyntaxKind.InterfaceKeyword:
                case SyntaxKind.对象关键字_:
                case SyntaxKind.结构关键字_:
                case SyntaxKind.别名关键字_:
                case SyntaxKind.测试关键字_:
                case SyntaxKind.断言关键字_:
                case SyntaxKind.指令关键字_:                    
                case SyntaxKind.输出转换词典头_:
                case SyntaxKind.输入转换词典头_:
                    return true;
                default:
                    return false;
            }
        }

        function isStartOfStatement(): boolean {
            switch (token()) {
                case SyntaxKind.SemicolonToken:
                case SyntaxKind.OpenBraceToken:
                case SyntaxKind.LetKeyword:
                case SyntaxKind.共享关键字_:
                case SyntaxKind.ConstKeyword:
                case SyntaxKind.IfKeyword:
                case SyntaxKind.ForKeyword:
                case SyntaxKind.ContinueKeyword:
                case SyntaxKind.BreakKeyword:
                case SyntaxKind.ReturnKeyword:
                case SyntaxKind.SwitchKeyword:
                case SyntaxKind.DeleteKeyword:
                case SyntaxKind.DebuggerKeyword:
                case SyntaxKind.ThrowKeyword:
                case SyntaxKind.TryKeyword:
                case SyntaxKind.CatchKeyword:
                case SyntaxKind.FinallyKeyword:
                case SyntaxKind.执行关键字_:
                case SyntaxKind.延迟关键字_:
                case SyntaxKind.版本关键字_:
                case SyntaxKind.断言关键字_:
                case SyntaxKind.同步关键字_:
                case SyntaxKind.指令语句_:
                case SyntaxKind.测试关键字_:
                case SyntaxKind.输出转换词典头_:
                case SyntaxKind.输入转换词典头_:
                    return true;
                default:
                    return isStartOfExpression();
            }
        }

        function 是导入从声明语句(): boolean {
            return lookAhead(前面是文本字面量);
        }

        function 前面是文本字面量(): boolean {
            return token() === SyntaxKind.StringLiteral;
        }

        function 解析导入从成员版本语句块() {
            const node = <导入从成员块_>createNode(SyntaxKind.导入从成员块_);
            if (parseExpected(SyntaxKind.OpenBraceToken)) {
                if (scanner.hasPrecedingLineBreak()) node.multiLine = true;
                node.statements = parseList(ParsingContext.解析导入从语句_, 解析导入从成员);
                parseExpected(SyntaxKind.CloseBraceToken);
            }
            return finishNode(node);
        }

        function 解析导入成员版本语句块() {
            const node = <导入成员块_>createNode(SyntaxKind.导入成员块_);
            if (parseExpected(SyntaxKind.OpenBraceToken)) {
                if (scanner.hasPrecedingLineBreak()) node.multiLine = true;
                node.statements = parseList(ParsingContext.解析导入语句_, 解析导入成员);
                parseExpected(SyntaxKind.CloseBraceToken);
            }
            return finishNode(node);
        }

        function 解析导入从成员(): 导入从成员_ | 导入从版本成员_ {
            const n = <导入从成员_ | 导入从版本成员_>createNodeWithJSDoc(SyntaxKind.Unknown);
            if (token() === SyntaxKind.版本关键字_) {
                const 储存的上下文 = contextFlags;
                setContextFlag(true, NodeFlags.在版本验证上下文_);
                n.kind = SyntaxKind.导入从版本成员_;
                parseExpected(SyntaxKind.版本关键字_);
                parseExpected(SyntaxKind.OpenParenToken);
                (<导入从版本成员_>n).expression = parseIdentifier();
                parseExpected(SyntaxKind.CloseParenToken);
                (<导入从版本成员_>n).thenStatement = 解析导入从成员版本语句块();
                (<导入从版本成员_>n).thenStatement.版本容器块种类 = 是版本另如容器块 ? 版本容器块种类_.是版本另如容器块_ : 版本容器块种类_.是版本容器块_;
                是版本另如容器块 = false;
                if (parseOptional(SyntaxKind.ElseKeyword)) {
                    if (parseOptional(SyntaxKind.ElseKeyword)) {
                        if (token() === SyntaxKind.版本关键字_) {
                            是版本另如容器块 = true;
                            (<导入从版本成员_>n).elseStatement = 解析导入从成员() as 导入从版本成员_;
                        }
                        else {
                            (<导入从版本成员_>n).elseStatement = 解析导入从成员版本语句块();
                            (<导入从成员块_>(<导入从版本成员_>n).elseStatement).版本容器块种类 = 版本容器块种类_.是版本否则容器块_;
                        }
                    }
                }
                const ret = finishNode(n);
                setContextFlag(false, NodeFlags.在版本验证上下文_);
                contextFlags = 储存的上下文;
                return ret;
            }
            n.kind = SyntaxKind.导入从成员_;
            let 名称 = parseIdentifier();
            let 别名: Identifier | undefined
            if (parseOptional(SyntaxKind.ColonToken)) {
                别名 = 名称;
                名称 = parseIdentifier();
            }
            (<导入从成员_>n).name = 名称;
            (<导入从成员_>n).别名 = 别名;
            解析分号或逗号();
            return finishNode(n);
        }

        function 解析导入成员(): 导入成员_ | 导入版本成员_ {
            const n = <导入成员_ | 导入版本成员_>createNodeWithJSDoc(SyntaxKind.Unknown);
            if (token() === SyntaxKind.版本关键字_) {
                const 储存的上下文 = contextFlags;
                setContextFlag(true, NodeFlags.在版本验证上下文_);
                n.kind = SyntaxKind.导入版本成员_;
                parseExpected(SyntaxKind.版本关键字_);
                parseExpected(SyntaxKind.OpenParenToken);
                (<导入版本成员_>n).expression = parseIdentifier();
                parseExpected(SyntaxKind.CloseParenToken);
                (<导入版本成员_>n).thenStatement = 解析导入成员版本语句块();
                (<导入版本成员_>n).thenStatement.版本容器块种类 = 是版本另如容器块 ? 版本容器块种类_.是版本另如容器块_ : 版本容器块种类_.是版本容器块_;
                是版本另如容器块 = false;
                if (parseOptional(SyntaxKind.ElseKeyword)) {
                    if (parseOptional(SyntaxKind.ElseKeyword)) {
                        if (token() === SyntaxKind.版本关键字_) {
                            是版本另如容器块 = true;
                            (<导入版本成员_>n).elseStatement = 解析导入成员() as 导入版本成员_;
                        }
                        else {
                            (<导入版本成员_>n).elseStatement = 解析导入成员版本语句块();
                            (<导入成员块_>(<导入版本成员_>n).elseStatement).版本容器块种类 = 版本容器块种类_.是版本否则容器块_;
                        }
                    }
                }
                const ret = finishNode(n);
                setContextFlag(false, NodeFlags.在版本验证上下文_);
                contextFlags = 储存的上下文;
                return ret;
            }
            n.kind = SyntaxKind.导入成员_;
            if (token() !== SyntaxKind.StringLiteral) {
                (<导入成员_>n).别名 = parseIdentifier();
                parseExpected(SyntaxKind.ColonToken);
            }
            (<导入成员_>n).模块名 = <StringLiteral>parseLiteralLikeNode(SyntaxKind.StringLiteral);
            if (!(<导入成员_>n)?.模块名.text) {
                parseErrorAt((<导入成员_>n)?.模块名.pos, (<导入成员_>n)?.模块名.end, Diagnostics.模块名不能为空);
            }
            parseSemicolon();
            return finishNode(n);
        }

        function 解析导入声明或导入从声明(n?: 导入声明_ | 导入从声明_): 导入声明_ | 导入从声明_ {
            n = n || <导入声明_ | 导入从声明_>createNodeWithJSDoc(SyntaxKind.Unknown);
            parseExpected(SyntaxKind.ImportKeyword);
            if (是导入从声明语句()) {
                n.kind = SyntaxKind.导入从声明_;
                (<导入从声明_>n).模块名 = <StringLiteral>parseLiteralLikeNode(SyntaxKind.StringLiteral);
                parseExpected(SyntaxKind.OpenBraceToken);
                n.导入组 = parseList(ParsingContext.解析导入从语句_, 解析导入从成员);
                parseExpected(SyntaxKind.CloseBraceToken);
            }
            else {
                n.kind = SyntaxKind.导入声明_;
                parseExpected(SyntaxKind.OpenBraceToken);
                n.导入组 = parseList(ParsingContext.解析导入语句_, 解析导入成员);
                parseExpected(SyntaxKind.CloseBraceToken);
            }
            return finishNode(n);
        }

        function 解析程序声明(n: 程序声明_): 程序声明_ {
            n.kind = SyntaxKind.程序声明_;
            if (parseOptional(SyntaxKind.程序关键字_)) {
                if (token() === SyntaxKind.启动关键字_) {
                    n.是启动声明 = true;
                    sourceFile.是启动文件 = true;
                    n.name = parseIdentifierName();
                }
                else if (token() === SyntaxKind.全局关键字_) {
                    n.name = parseIdentifierName();
                }
                else {
                    n.name = parseIdentifier();
                }
            }
            const 有括号 = parseOptional(SyntaxKind.OpenBraceToken);
            n.statements = parseList(ParsingContext.程序集顶级语句_, 解析程序集顶级语句);
            if (有括号) parseExpected(SyntaxKind.CloseBraceToken);
            return finishNode(n);
        }

        function 解析指令语句(node?: 指令语句_): 指令语句_ {
            if (!node) {
                node = <指令语句_>createNode(SyntaxKind.指令语句_);
            }
            else{
                node.kind = SyntaxKind.指令语句_;
            }
            parseExpected(SyntaxKind.指令关键字_);
            parseExpected(SyntaxKind.OpenParenToken);
            node.参数 = <StringLiteral>parseLiteralLikeNode(SyntaxKind.StringLiteral);
            parseExpected(SyntaxKind.CloseParenToken);
            parseOptionalToken(SyntaxKind.SemicolonToken);
            return finishNode(node);
        }

        function 解析同步语句(): 同步语句_ {
            const node = <同步语句_>createNode(SyntaxKind.同步语句_);
            parseExpected(SyntaxKind.同步关键字_);
            if (token() === SyntaxKind.OpenParenToken) {
                node.arguments = parseArgumentList();
            }
            parseExpected(SyntaxKind.OpenBraceToken)
            node.statements = parseList(ParsingContext.BlockStatements, 解析语句);
            parseExpected(SyntaxKind.CloseBraceToken);
            return finishNode(node);
        }

        function 解析测试单元语句(node: 测试单元语句_): 测试单元语句_ {
            setContextFlag(true, NodeFlags.在测试单元上下文_)
            node.kind = SyntaxKind.测试单元语句_;
            parseExpected(SyntaxKind.测试关键字_);
            parseExpected(SyntaxKind.OpenBraceToken);
            node.statements = parseList(ParsingContext.源码顶级语句_, 解析源码顶级语句);
            parseExpected(SyntaxKind.CloseBraceToken);
            node.版本容器块种类 = 版本容器块种类_.是测试单元_;
            const retNode = finishNode(node);
            setContextFlag(false, NodeFlags.在测试单元上下文_);
            return retNode;
        }

        function 解析启动函数(node: 启动函数声明_): FunctionDeclaration {
            node.kind = SyntaxKind.FunctionDeclaration;
            node.是启动函数 = true
            node.name = parseIdentifierName();
            fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
            node.body = parseFunctionBlockOrSemicolon(0, Diagnostics.or_expected);
            return finishNode(node);
        }

        function 解析初始函数(node: 初始函数声明_): FunctionDeclaration {
            node.kind = SyntaxKind.FunctionDeclaration;
            node.是初始函数 = true
            node.name = parseIdentifierName();
            fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
            node.body = parseFunctionBlockOrSemicolon(0, Diagnostics.or_expected);
            return finishNode(node);
        }

        function 解析程序集顶级语句(): 程序集顶级语句_ {
            const n = <Statement>createNodeWithJSDoc(SyntaxKind.Unknown);
            switch (token()) {
                case SyntaxKind.LetKeyword:
                case SyntaxKind.ConstKeyword:
                case SyntaxKind.共享关键字_:
                    return parseVariableStatement(<VariableStatement>n, true);
                case SyntaxKind.方法关键字_:
                    return 解析方法声明(<MethodDeclaration>n);
                case SyntaxKind.FunctionKeyword:
                    return parseFunctionDeclaration(<FunctionDeclaration>n) as FunctionDeclaration;
                case SyntaxKind.对象关键字_:
                    return 解析对象声明(<对象声明_>n);
                case SyntaxKind.结构关键字_:
                    return 解析结构声明(<结构声明_>n);
                case SyntaxKind.InterfaceKeyword:
                    return parseInterfaceDeclaration(<InterfaceDeclaration>n);
                case SyntaxKind.EnumKeyword:
                    return parseEnumDeclaration(<EnumDeclaration>n);
                case SyntaxKind.TypeKeyword:
                case SyntaxKind.别名关键字_:
                    return 解析类型别名或类型声明(<别名声明节点_>n);
                case SyntaxKind.初始关键字_:
                    return 解析初始函数(<初始函数声明_>n);
                case SyntaxKind.启动关键字_:
                    return 解析启动函数(<启动函数声明_>n);
                case SyntaxKind.指令关键字_:
                    return 解析指令语句(<指令语句_>n);
                case SyntaxKind.测试关键字_:
                    return 解析测试单元语句(<测试单元语句_>n);
                case SyntaxKind.断言关键字_:
                    return 解析断言语句(<断言语句_>n);
                case SyntaxKind.版本关键字_:
                    return 解析版本语句(<版本语句_ | 版本表达式语句_>n, true);
                default:
                    return undefined!;
            }
        }

        function 解析源码顶级语句(): 导入声明_ | 导入从声明_ | 程序声明_ | NotEmittedStatement | Statement {
            const n = <Statement>createNodeWithJSDoc(SyntaxKind.Unknown)
            switch (token()) {
                case SyntaxKind.ImportKeyword:
                    return 解析导入声明或导入从声明(<导入声明_ | 导入从声明_>n);
                case SyntaxKind.版本关键字_:
                    return 解析源码级版本语句(<版本语句_>n);
                default:
                    if (contextFlags & NodeFlags.在测试单元上下文_ || contextFlags & NodeFlags.在版本验证上下文_) {
                        return 解析程序集顶级语句();
                    }
                    return 解析程序声明(<程序声明_>n);
            }
        }

        function 解析语句(): Statement {
            switch (token()) {
                case SyntaxKind.SemicolonToken:
                    return parseEmptyStatement();
                case SyntaxKind.OpenBraceToken:
                    return parseBlock(/*ignoreMissingOpenBrace*/ false);
                case SyntaxKind.LetKeyword:
                case SyntaxKind.ConstKeyword:
                case SyntaxKind.共享关键字_:
                    return parseVariableStatement(<VariableStatement>createNodeWithJSDoc(SyntaxKind.VariableDeclaration));
                case SyntaxKind.IfKeyword:
                case SyntaxKind.另如关键字_:
                    return parseIfStatement(token());
                case SyntaxKind.ForKeyword:
                    return parseForOrForOfStatement();
                case SyntaxKind.ContinueKeyword:
                    return parseBreakOrContinueStatement(SyntaxKind.ContinueStatement);
                case SyntaxKind.BreakKeyword:
                    return parseBreakOrContinueStatement(SyntaxKind.BreakStatement);
                case SyntaxKind.DeleteKeyword:
                    return 解析删除语句()
                case SyntaxKind.延迟关键字_:
                    return 解析延迟语句();
                case SyntaxKind.ReturnKeyword:
                    return parseReturnStatement();
                case SyntaxKind.SwitchKeyword:
                    return parseSwitchStatement();
                case SyntaxKind.ThrowKeyword:
                    return parseThrowStatement();
                case SyntaxKind.断言关键字_:
                    return 解析断言语句();
                case SyntaxKind.同步关键字_:
                    return 解析同步语句();
                case SyntaxKind.指令关键字_:
                    return 解析指令语句();
                case SyntaxKind.版本关键字_:
                    return 解析版本语句();
                case SyntaxKind.TryKeyword:
                case SyntaxKind.CatchKeyword:
                case SyntaxKind.FinallyKeyword:
                    return parseTryStatement();
                case SyntaxKind.DebuggerKeyword:
                    return parseDebuggerStatement();
                case SyntaxKind.基类关键字_:
                    return 解析基类调用();
            }
            return parseExpressionOrLabeledStatement();
        }

        function 转换简洁变量语句为类型声明列表(expression: 简洁变量语句_): VariableDeclarationList {
            for (let i = 0; i < expression.initializers.length; i++) {
                let intit = expression.initializers[i];
                expression.declarations[i].initializer = intit;
                expression.declarations[i].end = intit.end;
                expression.declarations.end = intit.end;
            }
            const declarationList = <VariableDeclarationList>createNode(SyntaxKind.VariableDeclarationList, expression.pos);
            declarationList.flags |= NodeFlags.Let | expression.flags;
            declarationList.declarations = expression.declarations;
            declarationList.end = expression.end;
            return finishNode(declarationList);
        }

        function 解析延迟语句() {
            const node = <延迟语句_>createNode(SyntaxKind.延迟语句_);
            parseExpected(SyntaxKind.延迟关键字_);
            node.expression = parseExpression();            
            parseSemicolon();
            return finishNode(node);
        }

        function 解析删除语句() {
            const node = <删除语句_>createNode(SyntaxKind.删除语句_);
            parseExpected(SyntaxKind.DeleteKeyword);
            node.expression = parseExpression();
            return finishNode(node);
        }

        function parseFunctionBlockOrSemicolon(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block | undefined {
            if (token() !== SyntaxKind.OpenBraceToken && canParseSemicolon()) {
                parseSemicolon();
                return;
            }

            return parseFunctionBlock(flags, diagnosticMessage);
        }

        // DECLARATIONS
        function isIdentifierOrPattern() {
            return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken || isIdentifier();
        }

        function parseIdentifierOrPattern(): Identifier {
            return parseIdentifier();
        }

        function parseVariableDeclarationAllowExclamation() {
            return parseVariableDeclaration(/*allowExclamation*/ true);
        }

        function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration {
            const node = <VariableDeclaration>createNode(SyntaxKind.VariableDeclaration);
            node.name = parseIdentifierOrPattern();

            if (allowExclamation && node.name.kind === SyntaxKind.Identifier &&
                token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
                node.exclamationToken = parseTokenNode<Token<SyntaxKind.ExclamationToken>>();
            }
            node.type = parseTypeAnnotation();
            if (!isInOrOfKeyword(token())) {
                node.initializer = parseInitializer();
            }
            node.是全局变量 = 正在编译全局变量;
            return finishNode(node);
        }

        function parseVariableDeclarationList(inForStatementInitializer: boolean): VariableDeclarationList {
            const node = <VariableDeclarationList>createNode(SyntaxKind.VariableDeclarationList);
            switch (token()) {
                case SyntaxKind.LetKeyword:
                    node.flags |= NodeFlags.Let;
                    nextToken();
                    break;
                case SyntaxKind.共享关键字_:
                    node.flags |= NodeFlags.共享_;
                    nextToken();
                    break;
                case SyntaxKind.ConstKeyword:
                    node.flags |= NodeFlags.Const;
                    nextToken();
                    break;
                default:
                    if (!inForStatementInitializer) Debug.fail();
            }

            // The user may have written the following:
            //
            //    for (let of X) { }
            //
            // In this case, we want to parse an empty declaration list, and then parse 'of'
            // as a keyword. The reason this is not automatic is that 'of' is a valid identifier.
            // So we need to look ahead to determine if 'of' should be treated as a keyword in
            // this context.
            // The checker will then give an error that there is an empty declaration list.
            if (token() === SyntaxKind.OfKeyword && lookAhead(canFollowContextualOfKeyword)) {
                node.declarations = createMissingList<VariableDeclaration>();
            }
            else {
                node.declarations = parseDelimitedList(ParsingContext.VariableDeclarations,
                    inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation);
            }
            node.是全局变量 = 正在编译全局变量;
            return finishNode(node);
        }

        function 前方有属于关键字() {
            nextToken()
            while (token() !== SyntaxKind.EndOfFileToken && !scanner.hasPrecedingLineBreak()) {
                if (token() === SyntaxKind.OfKeyword) {
                    return true;
                }
                nextToken()
            }
            return false;
        }

        function canFollowContextualOfKeyword(): boolean {
            return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken;
        }

        function parseVariableStatement(node: VariableStatement, 是全局变量 = false): VariableStatement {
            node.kind = SyntaxKind.VariableStatement;
            正在编译全局变量 = 是全局变量;
            node.declarationList = parseVariableDeclarationList(/*inForStatementInitializer*/ false);
            node.是全局变量 = 是全局变量            
            正在编译全局变量 = false;
            parseSemicolon();
            return finishNode(node);
        }

        function parseFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration {
            node.kind = SyntaxKind.FunctionDeclaration;
            parseExpected(SyntaxKind.FunctionKeyword);
            if (token() === SyntaxKind.启动关键字_) {
                (<启动函数声明_>node).是启动函数 = true;
                (<启动函数声明_>node).name = parseIdentifierName();
            }
            else if (token() === SyntaxKind.初始关键字_) {
                (<初始函数声明_>node).是初始函数 = true;
                (<初始函数声明_>node).name = parseIdentifierName();

            }
            else {
                node.name = parseIdentifier();
            }
            fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
            node.body = parseFunctionBlockOrSemicolon(0, Diagnostics.or_expected);
            return finishNode(node);
        }


        function 解析方法声明(node: MethodDeclaration, 诊断消息?: DiagnosticMessage): MethodDeclaration {
            node.kind = SyntaxKind.MethodDeclaration;
            parseExpected(SyntaxKind.方法关键字_);
            let 是指针接受者 = false;
            let pos = scanner.getStartPos()
            if (parseOptional(SyntaxKind.AsteriskToken)) {
                是指针接受者 = true;
            }
            let 接受者名称 = parseEntityName(false);
            let 接受者 = createNode(SyntaxKind.TypeReference, pos);
            if (isQualifiedName(接受者名称)) {
                if (token() !== SyntaxKind.中点号_) {
                    node.name = 接受者名称.right;
                    (<TypeReferenceNode>接受者).typeName = 接受者名称.left;
                    finishNode(接受者, 接受者名称.left.end);
                }
                else {
                    parseExpected(SyntaxKind.中点号_);
                    node.name = parseIdentifier();
                    (<TypeReferenceNode>接受者).typeName = 接受者名称;
                    finishNode(接受者, 接受者名称.right.end);
                }
            }
            else if (ts.isIdentifier(接受者名称)) {
                parseOptional(SyntaxKind.中点号_)
                node.name = parseIdentifier();
                (<TypeReferenceNode>接受者).typeName = 接受者名称;
                finishNode(接受者, 接受者名称.end);
            }
            else return createMissingNode(SyntaxKind.MethodDeclaration, true, Diagnostics.外部方法接受者必须是一个引用类型节点或指针类型节点);
            if (是指针接受者) {
                const 指针接受者 = <指针类型节点_>createNode(SyntaxKind.指针类型_, pos);
                指针接受者.type = <TypeReferenceNode>接受者;
                接受者 = finishNode(指针接受者, 接受者.end);
            }
            node.接受者 = <TypeReferenceNode>接受者;
            fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
            node.body = parseFunctionBlockOrSemicolon(0, 诊断消息);
            const 外部方法 = finishNode(node);
            (外部方法收集器 || (外部方法收集器 = [])).push(外部方法);
            return 外部方法;
        }

        /*
         * There are situations in which a modifier like 'const' will appear unexpectedly, such as on a class member.
         * In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect
         * and turns it into a standalone declaration), then it is better to parse it and report an error later.
         *
         * In such situations, 'permitInvalidConstAsModifier' should be set to true.
         */
        function parseHeritageClauses(): NodeArray<HeritageClause> | undefined {
            // ClassTail[Yield,Await] : (Modified) See 14.5
            //      ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }

            if (isHeritageClause()) {
                return parseList(ParsingContext.HeritageClauses, parseHeritageClause);
            }

            return undefined;
        }

        function parseHeritageClause(): HeritageClause {
            const tok = token();
            Debug.assert(tok === SyntaxKind.ColonToken); // isListElement() should ensure this.
            const node = <HeritageClause>createNode(SyntaxKind.HeritageClause);
            nextToken();
            node.types = parseDelimitedList(ParsingContext.HeritageClauseElement, parseExpressionWithTypeArguments);
            return finishNode(node);
        }

        function parseExpressionWithTypeArguments(): ExpressionWithTypeArguments {
            const node = <ExpressionWithTypeArguments>createNode(SyntaxKind.ExpressionWithTypeArguments);
            node.expression = parseLeftHandSideExpressionOrHigher();
            node.typeArguments = tryParseTypeArguments();
            return finishNode(node);
        }

        function tryParseTypeArguments(): NodeArray<TypeNode> | undefined {
            return token() === SyntaxKind.LessThanToken ?
                parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken) : undefined;
        }

        function isHeritageClause(): boolean {
            return token() === SyntaxKind.ColonToken;
        }

        function parseInterfaceDeclaration(node: InterfaceDeclaration): InterfaceDeclaration {
            node.kind = SyntaxKind.InterfaceDeclaration;
            parseExpected(SyntaxKind.InterfaceKeyword);
            node.name = parseIdentifier();
            node.typeParameters = parseTypeParameters();
            setContextFlag(true, NodeFlags.在继承条款上下文_);
            node.heritageClauses = parseHeritageClauses();
            setContextFlag(false, NodeFlags.在继承条款上下文_);
            node.members = 做禁止属性签名上下文(parseObjectTypeMembers);
            return finishNode(node);
        }

        function 解析对象声明(node: 对象声明_): 对象声明_ {
            node.kind = SyntaxKind.对象声明_;
            parseExpected(SyntaxKind.对象关键字_);
            node.name = parseIdentifier();
            node.typeParameters = parseTypeParameters();
            // 要设置继承条款上下文
            setContextFlag(true, NodeFlags.在继承条款上下文_);
            node.heritageClauses = parseHeritageClauses();
            setContextFlag(false, NodeFlags.在继承条款上下文_);
            parseExpected(SyntaxKind.OpenBraceToken);
            node.members = parseList(ParsingContext.对象体成员_, 解析属性或内部方法声明);
            parseExpected(SyntaxKind.CloseBraceToken);
            return finishNode(node);
        }

        function 解析结构声明(node: 结构声明_): 结构声明_ {
            node.kind = SyntaxKind.结构声明_;
            parseExpected(SyntaxKind.结构关键字_);
            node.name = parseIdentifier();
            node.typeParameters = parseTypeParameters();
            parseExpected(SyntaxKind.OpenBraceToken);
            node.members = parseList(ParsingContext.对象体成员_, 解析属性或内部方法声明);
            parseExpected(SyntaxKind.CloseBraceToken);
            return finishNode(node);
        }

        function 解析类型别名或类型声明(node: 别名声明节点_ | 类型声明节点_): 别名声明节点_ | 类型声明节点_ {
            let 是类型声明 = false
            if (parseOptional(SyntaxKind.别名关键字_)) {
                node.kind = SyntaxKind.别名声明_;
            }
            else if (parseOptional(SyntaxKind.TypeKeyword)) {
                node.kind = SyntaxKind.类型声明_;
                是类型声明 = true
            }
            node.name = parseIdentifier();
            node.typeParameters = parseTypeParameters();
            parseExpected(SyntaxKind.EqualsToken);
            node.type = parseType();

            if (是类型声明 && parseOptional(SyntaxKind.OpenBraceToken)) {
                (<类型声明节点_>node).members = parseList(ParsingContext.对象体成员_, 仅解析内部方法声明);
                // 编译方法
                parseExpected(SyntaxKind.CloseBraceToken);
            }
            parseSemicolon();
            return finishNode(node);
        }

        // In an ambient declaration, the grammar only allows integer literals as initializers.
        // In a non-ambient declaration, the grammar allows uninitialized members only in a
        // ConstantEnumMemberSection, which starts at the beginning of an enum declaration
        // or any time an integer literal initializer is encountered.
        function parseEnumMember(): EnumMember {
            const node = <EnumMember>createNodeWithJSDoc(SyntaxKind.EnumMember);
            node.name = parsePropertyName();
            node.initializer = parseInitializer();
            return finishNode(node);
        }

        function parseEnumDeclaration(node: EnumDeclaration): EnumDeclaration {
            node.kind = SyntaxKind.EnumDeclaration;
            parseExpected(SyntaxKind.EnumKeyword);
            node.name = parseIdentifier();
            if (parseExpected(SyntaxKind.OpenBraceToken)) {
                node.members = parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember);
                parseExpected(SyntaxKind.CloseBraceToken);
            }
            else {
                node.members = createMissingList<EnumMember>();
            }
            return finishNode(node);
        }

        function nextTokenIsOpenParen() {
            return nextToken() === SyntaxKind.OpenParenToken;
        }

        function parsingContextErrors(context: ParsingContext): DiagnosticMessage {
            switch (context) {
                case ParsingContext.源码顶级语句_: return Diagnostics.不是源码级顶级语句;
                case ParsingContext.程序集顶级语句_: return Diagnostics.不是程序集级语句;
                case ParsingContext.BlockStatements: return Diagnostics.Declaration_or_statement_expected;
                case ParsingContext.SwitchClauses: return Diagnostics.case_or_default_expected;
                case ParsingContext.SwitchClauseStatements: return Diagnostics.Statement_expected;
                case ParsingContext.TypeMembers: return Diagnostics.Property_or_signature_expected;
                case ParsingContext.对象体成员_: return Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected;
                case ParsingContext.EnumMembers: return Diagnostics.Enum_member_expected;
                case ParsingContext.HeritageClauseElement: return Diagnostics.Expression_expected;
                case ParsingContext.VariableDeclarations: return Diagnostics.Variable_declaration_expected;
                case ParsingContext.ArgumentExpressions: return Diagnostics.Argument_expression_expected;
                case ParsingContext.ObjectLiteralMembers: return Diagnostics.Property_assignment_expected;
                case ParsingContext.初始化成员_: return Diagnostics.Property_assignment_expected;
                case ParsingContext.ArrayLiteralMembers: return Diagnostics.Expression_or_comma_expected;
                case ParsingContext.JSDocParameters: return Diagnostics.Parameter_declaration_expected;
                case ParsingContext.Parameters: return Diagnostics.Parameter_declaration_expected;
                case ParsingContext.TypeParameters: return Diagnostics.Type_parameter_declaration_expected;
                case ParsingContext.TypeArguments: return Diagnostics.Type_argument_expected;
                case ParsingContext.TupleElementTypes: return Diagnostics.Type_expected;
                case ParsingContext.HeritageClauses: return Diagnostics.Unexpected_token_expected;
                case ParsingContext.解析导入从语句_: return Diagnostics.意外导入成员;
                case ParsingContext.解析导入语句_: return Diagnostics.意外导入成员;
                default: return undefined!; // TODO: GH#18217 `default: Debug.assertNever(context);`
            }
        }

        const enum ParsingContext {
            源码顶级语句_,
            程序集顶级语句_,
            BlockStatements,           // Statements in block
            SwitchClauses,             // Clauses in switch statement
            SwitchClauseStatements,    // Statements in switch clause
            TypeMembers,               // Members in interface or type literal
            EnumMembers,               // Members in enum declaration
            HeritageClauseElement,     // Elements in a heritage clause
            VariableDeclarations,      // Variable declarations in variable statement
            ArgumentExpressions,       // Expressions in argument list
            ObjectLiteralMembers,      // Members in object literal
            ArrayLiteralMembers,       // Members in array literal
            Parameters,                // Parameters in parameter list
            JSDocParameters,           // JSDoc parameters in parameter list of JSDoc function type
            TypeParameters,            // Type parameters in type parameter list
            TypeArguments,             // Type arguments in type argument list
            TupleElementTypes,         // Element types in tuple element type list
            HeritageClauses,           // Heritage clauses for a class or interface declaration.
            对象体成员_,
            解析导入从语句_,
            解析导入语句_,
            返回值类型成员_,
            初始化成员_,
            Count                      // Number of parsing contexts
        }

        const enum Tristate {
            False,
            True,
            Unknown
        }

        export namespace JSDocParser {
            // Parses out a JSDoc type expression.
            export function parseJSDocTypeExpression(mayOmitBraces?: boolean): JSDocTypeExpression {
                const result = <JSDocTypeExpression>createNode(SyntaxKind.JSDocTypeExpression);

                const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken);
                result.type = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType);
                if (!mayOmitBraces || hasBrace) {
                    parseExpectedJSDoc(SyntaxKind.CloseBraceToken);
                }

                fixupParentReferences(result);
                return finishNode(result);
            }

            export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined {
                initializeState(content,  /*_syntaxCursor:*/ undefined);
                sourceFile = <SourceFile>{ text: content };
                const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length));
                const diagnostics = parseDiagnostics;
                clearState();

                return jsDoc ? { jsDoc, diagnostics } : undefined;
            }

            export function 编译转换词典(parent: HasJSDoc, start: number, length: number): 转换词典语句_ | undefined {
                const saveToken = currentToken;
                const saveParseDiagnosticsLength = parseDiagnostics.length;
                const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode;

                const comment = doInsideOfContext(NodeFlags.转换词典上下文_, () => 编译转换词典平台(start, length));
                if (comment) {
                    comment.parent = parent;
                }
                currentToken = saveToken;
                parseDiagnostics.length = saveParseDiagnosticsLength;
                parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode;

                return comment;
            }

            export function parseJSDocComment(parent: HasJSDoc, start: number, length: number): JSDoc | undefined {
                const saveToken = currentToken;
                const saveParseDiagnosticsLength = parseDiagnostics.length;
                const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode;

                const comment = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length));
                if (comment) {
                    comment.parent = parent;
                }
                currentToken = saveToken;
                parseDiagnostics.length = saveParseDiagnosticsLength;
                parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode;

                return comment;
            }

            const enum JSDocState {
                BeginningOfLine,
                SawAsterisk,
                SavingComments,
                SavingBackticks, // NOTE: Only used when parsing tag comments
            }

            const enum PropertyLikeParse {
                Property = 1 << 0,
                Parameter = 1 << 1,
                CallbackParameter = 1 << 2,
            }

            function 编译转换词典平台(start = 0, length: number | undefined): 转换词典语句_ | undefined {
                const content = sourceText;
                const end = length === undefined ? content.length : start + length;
                length = end - start;
                let 种类: SyntaxKind.输入转换词典头_ | SyntaxKind.输出转换词典头_;
                let 元素: NodeArray<转换词典表达式_>;
                let 标识: Identifier;

                Debug.assert(start >= 0);
                Debug.assert(start <= end);
                Debug.assert(end <= content.length);
                if (!是转换词典类的文本(content, start)) {
                    return undefined;
                }
                return scanner.scanRange(start + 2, length - 2, () => {
                    下个词典语句令牌();
                    if (编译可选词典令牌(SyntaxKind.AtToken)) {
                        种类 = SyntaxKind.输入转换词典头_;
                    }
                    else if (编译可选词典令牌(SyntaxKind.井号令牌_)) {
                        种类 = SyntaxKind.输出转换词典头_;
                    }
                    标识 = parseIdentifier();
                    编译必须转换词典令牌(SyntaxKind.OpenBraceToken);
                    元素 = parseDelimitedList(ParsingContext.ObjectLiteralMembers, 解析转换词典表达式);
                    编译必须转换词典令牌(SyntaxKind.CloseBraceToken);
                    return 创建转换词典语句();
                });

                function 解析转换词典表达式(): 转换词典表达式_ {
                    const node = <转换词典表达式_>createNode(SyntaxKind.转换词典表达式_);
                    let 是字面量 = false;
                    if (token() !== SyntaxKind.Identifier) {
                        是字面量 = true;
                    }
                    node.键 = 是字面量 ? parseLiteralNode() as StringLiteral : parseIdentifier();
                    编译必须转换词典令牌(SyntaxKind.ColonToken)
                    if (是字面量 && token() === SyntaxKind.Identifier) {
                        parseErrorAt(node.pos, scanner.getTextPos(),Diagnostics.转换词典的键值表达式类型必须相同);
                    }
                    node.值 = 是字面量 ? parseLiteralNode() as StringLiteral : parseIdentifier();
                    return finishNode(node);
                }

                function 创建转换词典语句(): 转换词典语句_ {
                    const result = <转换词典语句_>createNode(SyntaxKind.转换词典语句_, start);
                    result.标识 = 标识;
                    result.种类 = 种类;
                    result.elements = 元素;
                    return finishNode(result, end);
                }

                function 编译可选词典令牌(t: 转换词典语句令牌_): boolean {
                    if (token() === t) {
                        下个词典语句令牌();
                        return true;
                    }
                    return false;
                }
            }

            function parseJSDocCommentWorker(start = 0, length: number | undefined): JSDoc | undefined {
                const content = sourceText;
                const end = length === undefined ? content.length : start + length;
                length = end - start;

                Debug.assert(start >= 0);
                Debug.assert(start <= end);
                Debug.assert(end <= content.length);

                // Check for /** (JSDoc opening part)
                if (!isJSDocLikeText(content, start)) {
                    return undefined;
                }

                let tags: JSDocTag[];
                let tagsPos: number;
                let tagsEnd: number;
                const comments: string[] = [];

                // + 3 for leading /**, - 5 in total for /** */
                return scanner.scanRange(start + 3, length - 5, () => {
                    // Initially we can parse out a tag.  We also have seen a starting asterisk.
                    // This is so that /** * @type */ doesn't parse.
                    let state = JSDocState.SawAsterisk;
                    let margin: number | undefined;
                    // + 4 for leading '/** '
                    let indent = start - Math.max(content.lastIndexOf("\n", start), 0) + 4;
                    function pushComment(text: string) {
                        if (!margin) {
                            margin = indent;
                        }
                        comments.push(text);
                        indent += text.length;
                    }

                    nextTokenJSDoc();
                    while (parseOptionalJsdoc(SyntaxKind.WhitespaceTrivia));
                    if (parseOptionalJsdoc(SyntaxKind.NewLineTrivia)) {
                        state = JSDocState.BeginningOfLine;
                        indent = 0;
                    }
                    loop: while (true) {
                        switch (token()) {
                            case SyntaxKind.AtToken:
                                if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) {
                                    removeTrailingWhitespace(comments);
                                    addTag(parseTag(indent));
                                    // NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag.
                                    // Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning
                                    // for malformed examples like `/** @param {string} x @returns {number} the length */`
                                    state = JSDocState.BeginningOfLine;
                                    margin = undefined;
                                }
                                else {
                                    pushComment(scanner.getTokenText());
                                }
                                break;
                            case SyntaxKind.NewLineTrivia:
                                comments.push(scanner.getTokenText());
                                state = JSDocState.BeginningOfLine;
                                indent = 0;
                                break;
                            case SyntaxKind.AsteriskToken:
                                const asterisk = scanner.getTokenText();
                                if (state === JSDocState.SawAsterisk || state === JSDocState.SavingComments) {
                                    // If we've already seen an asterisk, then we can no longer parse a tag on this line
                                    state = JSDocState.SavingComments;
                                    pushComment(asterisk);
                                }
                                else {
                                    // Ignore the first asterisk on a line
                                    state = JSDocState.SawAsterisk;
                                    indent += asterisk.length;
                                }
                                break;
                            case SyntaxKind.WhitespaceTrivia:
                                // only collect whitespace if we're already saving comments or have just crossed the comment indent margin
                                const whitespace = scanner.getTokenText();
                                if (state === JSDocState.SavingComments) {
                                    comments.push(whitespace);
                                }
                                else if (margin !== undefined && indent + whitespace.length > margin) {
                                    comments.push(whitespace.slice(margin - indent - 1));
                                }
                                indent += whitespace.length;
                                break;
                            case SyntaxKind.EndOfFileToken:
                                break loop;
                            default:
                                // Anything else is doc comment text. We just save it. Because it
                                // wasn't a tag, we can no longer parse a tag on this line until we hit the next
                                // line break.
                                state = JSDocState.SavingComments;
                                pushComment(scanner.getTokenText());
                                break;
                        }
                        nextTokenJSDoc();
                    }
                    removeLeadingNewlines(comments);
                    removeTrailingWhitespace(comments);
                    return createJSDocComment();
                });

                function removeLeadingNewlines(comments: string[]) {
                    while (comments.length && (comments[0] === "\n" || comments[0] === "\r")) {
                        comments.shift();
                    }
                }

                function removeTrailingWhitespace(comments: string[]) {
                    while (comments.length && comments[comments.length - 1].trim() === "") {
                        comments.pop();
                    }
                }

                function createJSDocComment(): JSDoc {
                    const result = <JSDoc>createNode(SyntaxKind.JSDocComment, start);
                    result.tags = tags && createNodeArray(tags, tagsPos, tagsEnd);
                    result.comment = comments.length ? comments.join("") : undefined;
                    return finishNode(result, end);
                }

                function isNextNonwhitespaceTokenEndOfFile(): boolean {
                    // We must use infinite lookahead, as there could be any number of newlines :(
                    while (true) {
                        nextTokenJSDoc();
                        if (token() === SyntaxKind.EndOfFileToken) {
                            return true;
                        }
                        if (!(token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia)) {
                            return false;
                        }
                    }
                }

                function skipWhitespace(): void {
                    if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
                        if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) {
                            return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range
                        }
                    }
                    while (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
                        nextTokenJSDoc();
                    }
                }

                function skipWhitespaceOrAsterisk(): string {
                    if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
                        if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) {
                            return ""; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range
                        }
                    }

                    let precedingLineBreak = scanner.hasPrecedingLineBreak();
                    let seenLineBreak = false;
                    let indentText = "";
                    while ((precedingLineBreak && token() === SyntaxKind.AsteriskToken) || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
                        indentText += scanner.getTokenText();
                        if (token() === SyntaxKind.NewLineTrivia) {
                            precedingLineBreak = true;
                            seenLineBreak = true;
                            indentText = "";
                        }
                        else if (token() === SyntaxKind.AsteriskToken) {
                            precedingLineBreak = false;
                        }
                        nextTokenJSDoc();
                    }
                    return seenLineBreak ? indentText : "";
                }

                function parseTag(margin: number) {
                    Debug.assert(token() === SyntaxKind.AtToken);
                    const start = scanner.getTokenPos();
                    nextTokenJSDoc();

                    const tagName = parseJSDocIdentifierName(/*message*/ undefined);
                    const indentText = skipWhitespaceOrAsterisk();

                    let tag: JSDocTag | undefined;
                    switch (tagName.escapedText) {
                        case "author":
                            tag = parseAuthorTag(start, tagName, margin);
                            break;
                        case "augments":
                        case "extends":
                            tag = parseAugmentsTag(start, tagName);
                            break;
                        case "this":
                            tag = parseThisTag(start, tagName);
                            break;
                        case "enum":
                            tag = parseEnumTag(start, tagName);
                            break;
                        case "arg":
                        case "argument":
                        case "param":
                            return parseParameterOrPropertyTag(start, tagName, PropertyLikeParse.Parameter, margin);
                        case "return":
                        case "returns":
                            tag = parseReturnTag(start, tagName);
                            break;
                        case "template":
                            tag = parseTemplateTag(start, tagName);
                            break;
                        case "type":
                            tag = parseTypeTag(start, tagName);
                            break;
                        case "typedef":
                            tag = parseTypedefTag(start, tagName, margin);
                            break;
                        case "callback":
                            tag = parseCallbackTag(start, tagName, margin);
                            break;
                        default:
                            tag = parseUnknownTag(start, tagName);
                            break;
                    }

                    if (!tag.comment) {
                        // some tags, like typedef and callback, have already parsed their comments earlier
                        if (!indentText) {
                            margin += tag.end - tag.pos;
                        }
                        tag.comment = parseTagComments(margin, indentText.slice(margin));
                    }
                    return tag;
                }

                function parseTagComments(indent: number, initialMargin?: string): string | undefined {
                    const comments: string[] = [];
                    let state = JSDocState.BeginningOfLine;
                    let margin: number | undefined;
                    function pushComment(text: string) {
                        if (!margin) {
                            margin = indent;
                        }
                        comments.push(text);
                        indent += text.length;
                    }
                    if (initialMargin) {
                        // jump straight to saving comments if there is some initial indentation
                        pushComment(initialMargin);
                        state = JSDocState.SavingComments;
                    }
                    let tok = token() as JSDocSyntaxKind;
                    loop: while (true) {
                        switch (tok) {
                            case SyntaxKind.NewLineTrivia:
                                if (state >= JSDocState.SawAsterisk) {
                                    state = JSDocState.BeginningOfLine;
                                    // don't use pushComment here because we want to keep the margin unchanged
                                    comments.push(scanner.getTokenText());
                                }
                                indent = 0;
                                break;
                            case SyntaxKind.AtToken:
                                if (state === JSDocState.SavingBackticks) {
                                    comments.push(scanner.getTokenText());
                                    break;
                                }
                                scanner.setTextPos(scanner.getTextPos() - 1);
                            // falls through
                            case SyntaxKind.EndOfFileToken:
                                // Done
                                break loop;
                            case SyntaxKind.WhitespaceTrivia:
                                if (state === JSDocState.SavingComments || state === JSDocState.SavingBackticks) {
                                    pushComment(scanner.getTokenText());
                                }
                                else {
                                    const whitespace = scanner.getTokenText();
                                    // if the whitespace crosses the margin, take only the whitespace that passes the margin
                                    if (margin !== undefined && indent + whitespace.length > margin) {
                                        comments.push(whitespace.slice(margin - indent));
                                    }
                                    indent += whitespace.length;
                                }
                                break;
                            case SyntaxKind.OpenBraceToken:
                                state = JSDocState.SavingComments;
                                if (lookAhead(() => nextTokenJSDoc() === SyntaxKind.AtToken && tokenIsIdentifierOrKeyword(nextTokenJSDoc()) && scanner.getTokenText() === "link")) {
                                    pushComment(scanner.getTokenText());
                                    nextTokenJSDoc();
                                    pushComment(scanner.getTokenText());
                                    nextTokenJSDoc();
                                }
                                pushComment(scanner.getTokenText());
                                break;
                            case SyntaxKind.BacktickToken:
                                if (state === JSDocState.SavingBackticks) {
                                    state = JSDocState.SavingComments;
                                }
                                else {
                                    state = JSDocState.SavingBackticks;
                                }
                                pushComment(scanner.getTokenText());
                                break;
                            default:
                                if (state !== JSDocState.SavingBackticks) {
                                    state = JSDocState.SavingComments; // leading identifiers start recording as well
                                }
                                pushComment(scanner.getTokenText());
                                break;
                        }
                        tok = nextTokenJSDoc();
                    }

                    removeLeadingNewlines(comments);
                    removeTrailingWhitespace(comments);
                    return comments.length === 0 ? undefined : comments.join("");
                }

                function parseUnknownTag(start: number, tagName: Identifier) {
                    const result = <JSDocTag>createNode(SyntaxKind.JSDocTag, start);
                    result.tagName = tagName;
                    return finishNode(result);
                }

                function addTag(tag: JSDocTag | undefined): void {
                    if (!tag) {
                        return;
                    }
                    if (!tags) {
                        tags = [tag];
                        tagsPos = tag.pos;
                    }
                    else {
                        tags.push(tag);
                    }
                    tagsEnd = tag.end;
                }

                function tryParseTypeExpression(): JSDocTypeExpression | undefined {
                    skipWhitespaceOrAsterisk();
                    return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;
                }

                function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } {
                    // Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar'
                    const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken);
                    if (isBracketed) {
                        skipWhitespace();
                    }
                    // a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild
                    const isBackquoted = parseOptionalJsdoc(SyntaxKind.BacktickToken);
                    const name = parseJSDocEntityName();
                    if (isBackquoted) {
                        parseExpectedTokenJSDoc(SyntaxKind.BacktickToken);
                    }
                    if (isBracketed) {
                        skipWhitespace();
                        // May have an optional default, e.g. '[foo = 42]'
                        if (parseOptionalToken(SyntaxKind.EqualsToken)) {
                            parseExpression();
                        }

                        parseExpected(SyntaxKind.CloseBracketToken);
                    }

                    return { name, isBracketed };
                }

                function isObjectOrObjectArrayTypeReference(node: TypeNode): boolean {
                    switch (node.kind) {
                        case SyntaxKind.ArrayType:
                            return isObjectOrObjectArrayTypeReference((node as ArrayTypeNode).elementType);
                        default:
                            return isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.escapedText === "Object";
                    }
                }

                function parseParameterOrPropertyTag(start: number, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag {
                    let typeExpression = tryParseTypeExpression();
                    let isNameFirst = !typeExpression;
                    skipWhitespaceOrAsterisk();

                    const { name, isBracketed } = parseBracketNameInPropertyAndParamTag();
                    skipWhitespace();

                    if (isNameFirst) {
                        typeExpression = tryParseTypeExpression();
                    }

                    const result = target === PropertyLikeParse.Property ?
                        <JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, start) :
                        <JSDocParameterTag>createNode(SyntaxKind.JSDocParameterTag, start);
                    const comment = parseTagComments(indent + scanner.getStartPos() - start);
                    const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target, indent);
                    if (nestedTypeLiteral) {
                        typeExpression = nestedTypeLiteral;
                        isNameFirst = true;
                    }
                    result.tagName = tagName;
                    result.typeExpression = typeExpression;
                    result.name = name;
                    result.isNameFirst = isNameFirst;
                    result.isBracketed = isBracketed;
                    result.comment = comment;
                    return finishNode(result);
                }

                function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) {
                    if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) {
                        const typeLiteralExpression = <JSDocTypeExpression>createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos());
                        let child: JSDocPropertyLikeTag | JSDocTypeTag | false;
                        let jsdocTypeLiteral: JSDocTypeLiteral;
                        const start = scanner.getStartPos();
                        let children: JSDocPropertyLikeTag[] | undefined;
                        while (child = tryParse(() => parseChildParameterOrPropertyTag(target, indent, name))) {
                            if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) {
                                children = append(children, child);
                            }
                        }
                        if (children) {
                            jsdocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, start);
                            jsdocTypeLiteral.jsDocPropertyTags = children;
                            if (typeExpression.type.kind === SyntaxKind.ArrayType) {
                                jsdocTypeLiteral.isArrayType = true;
                            }
                            typeLiteralExpression.type = finishNode(jsdocTypeLiteral);
                            return finishNode(typeLiteralExpression);
                        }
                    }
                }

                function parseReturnTag(start: number, tagName: Identifier): JSDocReturnTag {
                    if (some(tags, isJSDocReturnTag)) {
                        parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
                    }

                    const result = <JSDocReturnTag>createNode(SyntaxKind.JSDocReturnTag, start);
                    result.tagName = tagName;
                    result.typeExpression = tryParseTypeExpression();
                    return finishNode(result);
                }

                function parseTypeTag(start: number, tagName: Identifier): JSDocTypeTag {
                    if (some(tags, isJSDocTypeTag)) {
                        parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
                    }

                    const result = <JSDocTypeTag>createNode(SyntaxKind.JSDocTypeTag, start);
                    result.tagName = tagName;
                    result.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
                    return finishNode(result);
                }

                function parseAuthorTag(start: number, tagName: Identifier, indent: number): JSDocAuthorTag {
                    const result = <JSDocAuthorTag>createNode(SyntaxKind.JSDocAuthorTag, start);
                    result.tagName = tagName;

                    const authorInfoWithEmail = tryParse(() => tryParseAuthorNameAndEmail());
                    if (!authorInfoWithEmail) {
                        return finishNode(result);
                    }

                    result.comment = authorInfoWithEmail;

                    if (lookAhead(() => nextToken() !== SyntaxKind.NewLineTrivia)) {
                        const comment = parseTagComments(indent);
                        if (comment) {
                            result.comment += comment;
                        }
                    }

                    return finishNode(result);
                }

                function tryParseAuthorNameAndEmail(): string | undefined {
                    const comments: string[] = [];
                    let seenLessThan = false;
                    let seenGreaterThan = false;
                    let token = scanner.getToken();

                    loop: while (true) {
                        switch (token) {
                            case SyntaxKind.Identifier:
                            case SyntaxKind.WhitespaceTrivia:
                            case SyntaxKind.DotToken:
                            case SyntaxKind.AtToken:
                                comments.push(scanner.getTokenText());
                                break;
                            case SyntaxKind.LessThanToken:
                                if (seenLessThan || seenGreaterThan) {
                                    return;
                                }
                                seenLessThan = true;
                                comments.push(scanner.getTokenText());
                                break;
                            case SyntaxKind.GreaterThanToken:
                                if (!seenLessThan || seenGreaterThan) {
                                    return;
                                }
                                seenGreaterThan = true;
                                comments.push(scanner.getTokenText());
                                scanner.setTextPos(scanner.getTokenPos() + 1);
                                break loop;
                            case SyntaxKind.NewLineTrivia:
                            case SyntaxKind.EndOfFileToken:
                                break loop;
                        }

                        token = nextTokenJSDoc();
                    }

                    if (seenLessThan && seenGreaterThan) {
                        return comments.length === 0 ? undefined : comments.join("");
                    }
                }

                function parseAugmentsTag(start: number, tagName: Identifier): JSDocAugmentsTag {
                    const result = <JSDocAugmentsTag>createNode(SyntaxKind.JSDocAugmentsTag, start);
                    result.tagName = tagName;
                    result.class = parseExpressionWithTypeArgumentsForAugments();
                    return finishNode(result);
                }

                function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression } {
                    const usedBrace = parseOptional(SyntaxKind.OpenBraceToken);
                    const node = createNode(SyntaxKind.ExpressionWithTypeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression };
                    node.expression = parsePropertyAccessEntityNameExpression();
                    node.typeArguments = tryParseTypeArguments();
                    const res = finishNode(node);
                    if (usedBrace) {
                        parseExpected(SyntaxKind.CloseBraceToken);
                    }
                    return res;
                }

                function parsePropertyAccessEntityNameExpression() {
                    let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName();
                    while (parseOptional(SyntaxKind.DotToken)) {
                        const prop: PropertyAccessEntityNameExpression = createNode(SyntaxKind.PropertyAccessExpression, node.pos) as PropertyAccessEntityNameExpression;
                        prop.expression = node;
                        prop.name = parseJSDocIdentifierName();
                        node = finishNode(prop);
                    }
                    return node;
                }

                function parseThisTag(start: number, tagName: Identifier): JSDocThisTag {
                    const tag = <JSDocThisTag>createNode(SyntaxKind.JSDocThisTag, start);
                    tag.tagName = tagName;
                    tag.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
                    skipWhitespace();
                    return finishNode(tag);
                }

                function parseEnumTag(start: number, tagName: Identifier): JSDocEnumTag {
                    const tag = <JSDocEnumTag>createNode(SyntaxKind.JSDocEnumTag, start);
                    tag.tagName = tagName;
                    tag.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
                    skipWhitespace();
                    return finishNode(tag);
                }

                function parseTypedefTag(start: number, tagName: Identifier, indent: number): JSDocTypedefTag {
                    const typeExpression = tryParseTypeExpression();
                    skipWhitespaceOrAsterisk();

                    const typedefTag = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, start);
                    typedefTag.tagName = tagName;
                    typedefTag.fullName = parseJSDocTypeNameWithNamespace();
                    typedefTag.name = typedefTag.fullName
                    skipWhitespace();
                    typedefTag.comment = parseTagComments(indent);

                    typedefTag.typeExpression = typeExpression;
                    let end: number | undefined;
                    if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) {
                        let child: JSDocTypeTag | JSDocPropertyTag | false;
                        let jsdocTypeLiteral: JSDocTypeLiteral | undefined;
                        let childTypeTag: JSDocTypeTag | undefined;
                        while (child = tryParse(() => parseChildPropertyTag(indent))) {
                            if (!jsdocTypeLiteral) {
                                jsdocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, start);
                            }
                            if (child.kind === SyntaxKind.JSDocTypeTag) {
                                if (childTypeTag) {
                                    break;
                                }
                                else {
                                    childTypeTag = child;
                                }
                            }
                            else {
                                jsdocTypeLiteral.jsDocPropertyTags = append(jsdocTypeLiteral.jsDocPropertyTags as MutableNodeArray<JSDocPropertyTag>, child);
                            }
                        }
                        if (jsdocTypeLiteral) {
                            if (typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType) {
                                jsdocTypeLiteral.isArrayType = true;
                            }
                            typedefTag.typeExpression = childTypeTag && childTypeTag.typeExpression && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ?
                                childTypeTag.typeExpression :
                                finishNode(jsdocTypeLiteral);
                            end = typedefTag.typeExpression.end;
                        }
                    }

                    // Only include the characters between the name end and the next token if a comment was actually parsed out - otherwise it's just whitespace
                    return finishNode(typedefTag, end || typedefTag.comment !== undefined ? scanner.getStartPos() : (typedefTag.fullName || typedefTag.typeExpression || typedefTag.tagName).end);
                }

                function parseJSDocTypeNameWithNamespace(nested?: boolean) {
                    if (!tokenIsIdentifierOrKeyword(token())) {
                        return undefined;
                    }
                    const typeNameOrNamespaceName = parseJSDocIdentifierName();
                    if (nested) {
                        typeNameOrNamespaceName.isInJSDocNamespace = true;
                    }
                    return typeNameOrNamespaceName;
                }

                function parseCallbackTag(start: number, tagName: Identifier, indent: number): JSDocCallbackTag {
                    const callbackTag = createNode(SyntaxKind.JSDocCallbackTag, start) as JSDocCallbackTag;
                    callbackTag.tagName = tagName;
                    callbackTag.fullName = parseJSDocTypeNameWithNamespace();
                    callbackTag.name = callbackTag.fullName;
                    skipWhitespace();
                    callbackTag.comment = parseTagComments(indent);

                    let child: JSDocParameterTag | false;
                    const jsdocSignature = createNode(SyntaxKind.JSDocSignature, start) as JSDocSignature;
                    jsdocSignature.parameters = [];
                    while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag)) {
                        jsdocSignature.parameters = append(jsdocSignature.parameters as MutableNodeArray<JSDocParameterTag>, child);
                    }
                    const returnTag = tryParse(() => {
                        if (parseOptionalJsdoc(SyntaxKind.AtToken)) {
                            const tag = parseTag(indent);
                            if (tag && tag.kind === SyntaxKind.JSDocReturnTag) {
                                return tag as JSDocReturnTag;
                            }
                        }
                    });
                    if (returnTag) {
                        jsdocSignature.type = returnTag;
                    }
                    callbackTag.typeExpression = finishNode(jsdocSignature);
                    return finishNode(callbackTag);
                }

                function escapedTextsEqual(a: EntityName, b: EntityName): boolean {
                    while (!ts.isIdentifier(a) || !ts.isIdentifier(b)) {
                        if (!ts.isIdentifier(a) && !ts.isIdentifier(b) && a.right.escapedText === b.right.escapedText) {
                            a = a.left;
                            b = b.left;
                        }
                        else {
                            return false;
                        }
                    }
                    return a.escapedText === b.escapedText;
                }

                function parseChildPropertyTag(indent: number) {
                    return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | false;
                }

                function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
                    let canParseTag = true;
                    while (true) {
                        switch (nextTokenJSDoc()) {
                            case SyntaxKind.AtToken:
                                if (canParseTag) {
                                    const child = tryParseChildTag(target, indent);
                                    if (child && (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) &&
                                        target !== PropertyLikeParse.CallbackParameter &&
                                        name && (ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left))) {
                                        return false;
                                    }
                                    return child;
                                }
                                break;
                            case SyntaxKind.NewLineTrivia:
                                canParseTag = true;
                                break;
                            case SyntaxKind.Identifier:
                                canParseTag = false;
                                break;
                            case SyntaxKind.EndOfFileToken:
                                return false;
                        }
                    }
                }

                function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
                    Debug.assert(token() === SyntaxKind.AtToken);
                    const start = scanner.getStartPos();
                    nextTokenJSDoc();

                    const tagName = parseJSDocIdentifierName();
                    skipWhitespace();
                    let t: PropertyLikeParse;
                    switch (tagName.escapedText) {
                        case "type":
                            return target === PropertyLikeParse.Property && parseTypeTag(start, tagName);
                        case "prop":
                        case "property":
                            t = PropertyLikeParse.Property;
                            break;
                        case "arg":
                        case "argument":
                        case "param":
                            t = PropertyLikeParse.Parameter | PropertyLikeParse.CallbackParameter;
                            break;
                        default:
                            return false;
                    }
                    if (!(target & t)) {
                        return false;
                    }
                    return parseParameterOrPropertyTag(start, tagName, target, indent);
                }

                function parseTemplateTag(start: number, tagName: Identifier): JSDocTemplateTag {
                    // the template tag looks like '@template {Constraint} T,U,V'
                    let constraint: JSDocTypeExpression | undefined;
                    if (token() === SyntaxKind.OpenBraceToken) {
                        constraint = parseJSDocTypeExpression();
                    }

                    const typeParameters = [];
                    const typeParametersPos = getNodePos();
                    do {
                        skipWhitespace();
                        const typeParameter = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter);
                        typeParameter.name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces);
                        finishNode(typeParameter);
                        skipWhitespace();
                        typeParameters.push(typeParameter);
                    } while (parseOptionalJsdoc(SyntaxKind.CommaToken));

                    const result = <JSDocTemplateTag>createNode(SyntaxKind.JSDocTemplateTag, start);
                    result.tagName = tagName;
                    result.constraint = constraint;
                    result.typeParameters = createNodeArray(typeParameters, typeParametersPos);
                    finishNode(result);
                    return result;
                }

                function parseOptionalJsdoc(t: JSDocSyntaxKind): boolean {
                    if (token() === t) {
                        nextTokenJSDoc();
                        return true;
                    }
                    return false;
                }

                function parseJSDocEntityName(): EntityName {
                    let entity: EntityName = parseJSDocIdentifierName();
                    if (parseOptional(SyntaxKind.OpenBracketToken)) {
                        parseExpected(SyntaxKind.CloseBracketToken);
                        // Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking.
                        // Technically usejsdoc.org requires them for specifying a property of a type equivalent to Array<{ x: ...}>
                        // but it's not worth it to enforce that restriction.
                    }
                    while (parseOptional(SyntaxKind.DotToken)) {
                        const name = parseJSDocIdentifierName();
                        if (parseOptional(SyntaxKind.OpenBracketToken)) {
                            parseExpected(SyntaxKind.CloseBracketToken);
                        }
                        entity = createQualifiedName(entity, name);
                    }
                    return entity;
                }

                function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier {
                    if (!tokenIsIdentifierOrKeyword(token())) {
                        return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected);
                    }

                    identifierCount++;
                    const pos = scanner.getTokenPos();
                    const end = scanner.getTextPos();
                    const result = <Identifier>createNode(SyntaxKind.Identifier, pos);
                    if (token() !== SyntaxKind.Identifier) {
                        result.originalKeywordKind = token();
                    }
                    result.escapedText = internIdentifier(scanner.getTokenValue());
                    finishNode(result, end);

                    nextTokenJSDoc();
                    return result;
                }
            }
        }
    }

    namespace IncrementalParser {
        export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile {
            aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive);
            checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks);
            if (textChangeRangeIsUnchanged(textChangeRange)) {
                // if the text didn't change, then we can just return our current source file as-is.
                return sourceFile;
            }

            if (sourceFile.statements.length === 0) {
                // If we don't have any statements in the current source file, then there's no real
                // way to incrementally parse.  So just do a full parse instead.
                return Parser.parseSourceFile(sourceFile.fileName, newText, /*syntaxCursor*/ undefined, /*setParentNodes*/ true);
            }

            // Make sure we're not trying to incrementally update a source file more than once.  Once
            // we do an update the original source file is considered unusable from that point onwards.
            //
            // This is because we do incremental parsing in-place.  i.e. we take nodes from the old
            // tree and give them new positions and parents.  From that point on, trusting the old
            // tree at all is not possible as far too much of it may violate invariants.
            const incrementalSourceFile = <IncrementalNode><Node>sourceFile;
            Debug.assert(!incrementalSourceFile.hasBeenIncrementallyParsed);
            incrementalSourceFile.hasBeenIncrementallyParsed = true;

            const oldText = sourceFile.text;
            const syntaxCursor = createSyntaxCursor(sourceFile);

            // Make the actual change larger so that we know to reparse anything whose lookahead
            // might have intersected the change.
            const changeRange = extendToAffectedRange(sourceFile, textChangeRange);
            checkChangeRange(sourceFile, newText, changeRange, aggressiveChecks);

            // Ensure that extending the affected range only moved the start of the change range
            // earlier in the file.
            Debug.assert(changeRange.span.start <= textChangeRange.span.start);
            Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span));
            Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange)));

            // The is the amount the nodes after the edit range need to be adjusted.  It can be
            // positive (if the edit added characters), negative (if the edit deleted characters)
            // or zero (if this was a pure overwrite with nothing added/removed).
            const delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length;

            // If we added or removed characters during the edit, then we need to go and adjust all
            // the nodes after the edit.  Those nodes may move forward (if we inserted chars) or they
            // may move backward (if we deleted chars).
            //
            // Doing this helps us out in two ways.  First, it means that any nodes/tokens we want
            // to reuse are already at the appropriate position in the new text.  That way when we
            // reuse them, we don't have to figure out if they need to be adjusted.  Second, it makes
            // it very easy to determine if we can reuse a node.  If the node's position is at where
            // we are in the text, then we can reuse it.  Otherwise we can't.  If the node's position
            // is ahead of us, then we'll need to rescan tokens.  If the node's position is behind
            // us, then we'll need to skip it or crumble it as appropriate
            //
            // We will also adjust the positions of nodes that intersect the change range as well.
            // By doing this, we ensure that all the positions in the old tree are consistent, not
            // just the positions of nodes entirely before/after the change range.  By being
            // consistent, we can then easily map from positions to nodes in the old tree easily.
            //
            // Also, mark any syntax elements that intersect the changed span.  We know, up front,
            // that we cannot reuse these elements.
            updateTokenPositionsAndMarkElements(incrementalSourceFile,
                changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks);

            // Now that we've set up our internal incremental state just proceed and parse the
            // source file in the normal fashion.  When possible the parser will retrieve and
            // reuse nodes from the old tree.
            //
            // Note: passing in 'true' for setNodeParents is very important.  When incrementally
            // parsing, we will be reusing nodes from the old tree, and placing it into new
            // parents.  If we don't set the parents now, we'll end up with an observably
            // inconsistent tree.  Setting the parents on the new tree should be very fast.  We
            // will immediately bail out of walking any subtrees when we can see that their parents
            // are already correct.
            const result = Parser.parseSourceFile(sourceFile.fileName, newText, syntaxCursor, /*setParentNodes*/ true);
            return result;
        }

        function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
            if (isArray) {
                visitArray(<IncrementalNodeArray>element);
            }
            else {
                visitNode(<IncrementalNode>element);
            }
            return;

            function visitNode(node: IncrementalNode) {
                let text = "";
                if (aggressiveChecks && shouldCheckNode(node)) {
                    text = oldText.substring(node.pos, node.end);
                }

                // Ditch any existing LS children we may have created.  This way we can avoid
                // moving them forward.
                if (node._children) {
                    node._children = undefined;
                }

                node.pos += delta;
                node.end += delta;

                if (aggressiveChecks && shouldCheckNode(node)) {
                    Debug.assert(text === newText.substring(node.pos, node.end));
                }

                forEachChild(node, visitNode, visitArray);
                if (hasJSDocNodes(node)) {
                    for (const jsDocComment of node.jsDoc!) {
                        visitNode(<IncrementalNode><Node>jsDocComment);
                    }
                }
                if (有转换词典节点(node)) {
                    for (const dict of node.dict!) {
                        visitNode(<IncrementalNode><Node>dict);
                    }
                }
                checkNodePositions(node, aggressiveChecks);
            }

            function visitArray(array: IncrementalNodeArray) {
                array._children = undefined;
                array.pos += delta;
                array.end += delta;

                for (const node of array) {
                    visitNode(node);
                }
            }
        }

        function shouldCheckNode(node: Node) {
            switch (node.kind) {
                case SyntaxKind.StringLiteral:
                case SyntaxKind.字符字面量_:
                case SyntaxKind.NumericLiteral:
                case SyntaxKind.Identifier:
                    return true;
            }

            return false;
        }

        function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) {
            Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range");
            Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range");
            Debug.assert(element.pos <= element.end);

            // We have an element that intersects the change range in some way.  It may have its
            // start, or its end (or both) in the changed range.  We want to adjust any part
            // that intersects such that the final tree is in a consistent state.  i.e. all
            // children have spans within the span of their parent, and all siblings are ordered
            // properly.

            // We may need to update both the 'pos' and the 'end' of the element.

            // If the 'pos' is before the start of the change, then we don't need to touch it.
            // If it isn't, then the 'pos' must be inside the change.  How we update it will
            // depend if delta is positive or negative. If delta is positive then we have
            // something like:
            //
            //  -------------------AAA-----------------
            //  -------------------BBBCCCCCCC-----------------
            //
            // In this case, we consider any node that started in the change range to still be
            // starting at the same position.
            //
            // however, if the delta is negative, then we instead have something like this:
            //
            //  -------------------XXXYYYYYYY-----------------
            //  -------------------ZZZ-----------------
            //
            // In this case, any element that started in the 'X' range will keep its position.
            // However any element that started after that will have their pos adjusted to be
            // at the end of the new range.  i.e. any node that started in the 'Y' range will
            // be adjusted to have their start at the end of the 'Z' range.
            //
            // The element will keep its position if possible.  Or Move backward to the new-end
            // if it's in the 'Y' range.
            element.pos = Math.min(element.pos, changeRangeNewEnd);

            // If the 'end' is after the change range, then we always adjust it by the delta
            // amount.  However, if the end is in the change range, then how we adjust it
            // will depend on if delta is positive or negative.  If delta is positive then we
            // have something like:
            //
            //  -------------------AAA-----------------
            //  -------------------BBBCCCCCCC-----------------
            //
            // In this case, we consider any node that ended inside the change range to keep its
            // end position.
            //
            // however, if the delta is negative, then we instead have something like this:
            //
            //  -------------------XXXYYYYYYY-----------------
            //  -------------------ZZZ-----------------
            //
            // In this case, any element that ended in the 'X' range will keep its position.
            // However any element that ended after that will have their pos adjusted to be
            // at the end of the new range.  i.e. any node that ended in the 'Y' range will
            // be adjusted to have their end at the end of the 'Z' range.
            if (element.end >= changeRangeOldEnd) {
                // Element ends after the change range.  Always adjust the end pos.
                element.end += delta;
            }
            else {
                // Element ends in the change range.  The element will keep its position if
                // possible. Or Move backward to the new-end if it's in the 'Y' range.
                element.end = Math.min(element.end, changeRangeNewEnd);
            }

            Debug.assert(element.pos <= element.end);
            if (element.parent) {
                Debug.assert(element.pos >= element.parent.pos);
                Debug.assert(element.end <= element.parent.end);
            }
        }

        function checkNodePositions(node: Node, aggressiveChecks: boolean) {
            if (aggressiveChecks) {
                let pos = node.pos;
                const visitNode = (child: Node) => {
                    Debug.assert(child.pos >= pos);
                    pos = child.end;
                };
                if (hasJSDocNodes(node)) {
                    for (const jsDocComment of node.jsDoc!) {
                        visitNode(jsDocComment);
                    }
                }
                if (有转换词典节点(node)) {
                    for (const dict of node.dict!) {
                        visitNode(dict);
                    }
                }
                forEachChild(node, visitNode);
                Debug.assert(pos <= node.end);
            }
        }

        function updateTokenPositionsAndMarkElements(
            sourceFile: IncrementalNode,
            changeStart: number,
            changeRangeOldEnd: number,
            changeRangeNewEnd: number,
            delta: number,
            oldText: string,
            newText: string,
            aggressiveChecks: boolean): void {

            visitNode(sourceFile);
            return;

            function visitNode(child: IncrementalNode) {
                Debug.assert(child.pos <= child.end);
                if (child.pos > changeRangeOldEnd) {
                    // Node is entirely past the change range.  We need to move both its pos and
                    // end, forward or backward appropriately.
                    moveElementEntirelyPastChangeRange(child, /*isArray*/ false, delta, oldText, newText, aggressiveChecks);
                    return;
                }

                // Check if the element intersects the change range.  If it does, then it is not
                // reusable.  Also, we'll need to recurse to see what constituent portions we may
                // be able to use.
                const fullEnd = child.end;
                if (fullEnd >= changeStart) {
                    child.intersectsChange = true;
                    child._children = undefined;

                    // Adjust the pos or end (or both) of the intersecting element accordingly.
                    adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
                    forEachChild(child, visitNode, visitArray);
                    if (hasJSDocNodes(child)) {
                        for (const jsDocComment of child.jsDoc!) {
                            visitNode(<IncrementalNode><Node>jsDocComment);
                        }
                    }
                    if (有转换词典节点(child)) {
                        for (const dict of child.dict!) {
                            visitNode(<IncrementalNode><Node>dict);
                        }
                    }
                    checkNodePositions(child, aggressiveChecks);
                    return;
                }

                // Otherwise, the node is entirely before the change range.  No need to do anything with it.
                Debug.assert(fullEnd < changeStart);
            }

            function visitArray(array: IncrementalNodeArray) {
                Debug.assert(array.pos <= array.end);
                if (array.pos > changeRangeOldEnd) {
                    // Array is entirely after the change range.  We need to move it, and move any of
                    // its children.
                    moveElementEntirelyPastChangeRange(array, /*isArray*/ true, delta, oldText, newText, aggressiveChecks);
                    return;
                }

                // Check if the element intersects the change range.  If it does, then it is not
                // reusable.  Also, we'll need to recurse to see what constituent portions we may
                // be able to use.
                const fullEnd = array.end;
                if (fullEnd >= changeStart) {
                    array.intersectsChange = true;
                    array._children = undefined;

                    // Adjust the pos or end (or both) of the intersecting array accordingly.
                    adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
                    for (const node of array) {
                        visitNode(node);
                    }
                    return;
                }

                // Otherwise, the array is entirely before the change range.  No need to do anything with it.
                Debug.assert(fullEnd < changeStart);
            }
        }

        function extendToAffectedRange(sourceFile: SourceFile, changeRange: TextChangeRange): TextChangeRange {
            // Consider the following code:
            //      void foo() { /; }
            //
            // If the text changes with an insertion of / just before the semicolon then we end up with:
            //      void foo() { //; }
            //
            // If we were to just use the changeRange a is, then we would not rescan the { token
            // (as it does not intersect the actual original change range).  Because an edit may
            // change the token touching it, we actually need to look back *at least* one token so
            // that the prior token sees that change.
            const maxLookahead = 1;

            let start = changeRange.span.start;

            // the first iteration aligns us with the change start. subsequent iteration move us to
            // the left by maxLookahead tokens.  We only need to do this as long as we're not at the
            // start of the tree.
            for (let i = 0; start > 0 && i <= maxLookahead; i++) {
                const nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start);
                Debug.assert(nearestNode.pos <= start);
                const position = nearestNode.pos;

                start = Math.max(0, position - 1);
            }

            const finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span));
            const finalLength = changeRange.newLength + (changeRange.span.start - start);

            return createTextChangeRange(finalSpan, finalLength);
        }

        function findNearestNodeStartingBeforeOrAtPosition(sourceFile: SourceFile, position: number): Node {
            let bestResult: Node = sourceFile;
            let lastNodeEntirelyBeforePosition: Node | undefined;

            forEachChild(sourceFile, visit);

            if (lastNodeEntirelyBeforePosition) {
                const lastChildOfLastEntireNodeBeforePosition = getLastDescendant(lastNodeEntirelyBeforePosition);
                if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) {
                    bestResult = lastChildOfLastEntireNodeBeforePosition;
                }
            }

            return bestResult;

            function getLastDescendant(node: Node): Node {
                while (true) {
                    const lastChild = getLastChild(node);
                    if (lastChild) {
                        node = lastChild;
                    }
                    else {
                        return node;
                    }
                }
            }

            function visit(child: Node) {
                if (nodeIsMissing(child)) {
                    // Missing nodes are effectively invisible to us.  We never even consider them
                    // When trying to find the nearest node before us.
                    return;
                }

                // If the child intersects this position, then this node is currently the nearest
                // node that starts before the position.
                if (child.pos <= position) {
                    if (child.pos >= bestResult.pos) {
                        // This node starts before the position, and is closer to the position than
                        // the previous best node we found.  It is now the new best node.
                        bestResult = child;
                    }

                    // Now, the node may overlap the position, or it may end entirely before the
                    // position.  If it overlaps with the position, then either it, or one of its
                    // children must be the nearest node before the position.  So we can just
                    // recurse into this child to see if we can find something better.
                    if (position < child.end) {
                        // The nearest node is either this child, or one of the children inside
                        // of it.  We've already marked this child as the best so far.  Recurse
                        // in case one of the children is better.
                        forEachChild(child, visit);

                        // Once we look at the children of this node, then there's no need to
                        // continue any further.
                        return true;
                    }
                    else {
                        Debug.assert(child.end <= position);
                        // The child ends entirely before this position.  Say you have the following
                        // (where $ is the position)
                        //
                        //      <complex expr 1> ? <complex expr 2> $ : <...> <...>
                        //
                        // We would want to find the nearest preceding node in "complex expr 2".
                        // To support that, we keep track of this node, and once we're done searching
                        // for a best node, we recurse down this node to see if we can find a good
                        // result in it.
                        //
                        // This approach allows us to quickly skip over nodes that are entirely
                        // before the position, while still allowing us to find any nodes in the
                        // last one that might be what we want.
                        lastNodeEntirelyBeforePosition = child;
                    }
                }
                else {
                    Debug.assert(child.pos > position);
                    // We're now at a node that is entirely past the position we're searching for.
                    // This node (and all following nodes) could never contribute to the result,
                    // so just skip them by returning 'true' here.
                    return true;
                }
            }
        }

        function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) {
            const oldText = sourceFile.text;
            if (textChangeRange) {
                Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length);

                if (aggressiveChecks || Debug.shouldAssert(AssertionLevel.VeryAggressive)) {
                    const oldTextPrefix = oldText.substr(0, textChangeRange.span.start);
                    const newTextPrefix = newText.substr(0, textChangeRange.span.start);
                    Debug.assert(oldTextPrefix === newTextPrefix);

                    const oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length);
                    const newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length);
                    Debug.assert(oldTextSuffix === newTextSuffix);
                }
            }
        }

        interface IncrementalElement extends TextRange {
            parent: Node;
            intersectsChange: boolean;
            length?: number;
            _children: Node[] | undefined;
        }

        export interface IncrementalNode extends Node, IncrementalElement {
            hasBeenIncrementallyParsed: boolean;
        }

        interface IncrementalNodeArray extends NodeArray<IncrementalNode>, IncrementalElement {
            length: number;
        }

        // Allows finding nodes in the source file at a certain position in an efficient manner.
        // The implementation takes advantage of the calling pattern it knows the parser will
        // make in order to optimize finding nodes as quickly as possible.
        export interface SyntaxCursor {
            currentNode(position: number): IncrementalNode;
        }

        function createSyntaxCursor(sourceFile: SourceFile): SyntaxCursor {
            let currentArray: NodeArray<Node> = sourceFile.statements;
            let currentArrayIndex = 0;

            Debug.assert(currentArrayIndex < currentArray.length);
            let current = currentArray[currentArrayIndex];
            let lastQueriedPosition = InvalidPosition.Value;

            return {
                currentNode(position: number) {
                    // Only compute the current node if the position is different than the last time
                    // we were asked.  The parser commonly asks for the node at the same position
                    // twice.  Once to know if can read an appropriate list element at a certain point,
                    // and then to actually read and consume the node.
                    if (position !== lastQueriedPosition) {
                        // Much of the time the parser will need the very next node in the array that
                        // we just returned a node from.So just simply check for that case and move
                        // forward in the array instead of searching for the node again.
                        if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) {
                            currentArrayIndex++;
                            current = currentArray[currentArrayIndex];
                        }

                        // If we don't have a node, or the node we have isn't in the right position,
                        // then try to find a viable node at the position requested.
                        if (!current || current.pos !== position) {
                            findHighestListElementThatStartsAtPosition(position);
                        }
                    }

                    // Cache this query so that we don't do any extra work if the parser calls back
                    // into us.  Note: this is very common as the parser will make pairs of calls like
                    // 'isListElement -> parseListElement'.  If we were unable to find a node when
                    // called with 'isListElement', we don't want to redo the work when parseListElement
                    // is called immediately after.
                    lastQueriedPosition = position;

                    // Either we don'd have a node, or we have a node at the position being asked for.
                    Debug.assert(!current || current.pos === position);
                    return <IncrementalNode>current;
                }
            };

            // Finds the highest element in the tree we can find that starts at the provided position.
            // The element must be a direct child of some node list in the tree.  This way after we
            // return it, we can easily return its next sibling in the list.
            function findHighestListElementThatStartsAtPosition(position: number) {
                // Clear out any cached state about the last node we found.
                currentArray = undefined!;
                currentArrayIndex = InvalidPosition.Value;
                current = undefined!;

                // Recurse into the source file to find the highest node at this position.
                forEachChild(sourceFile, visitNode, visitArray);
                return;

                function visitNode(node: Node) {
                    if (position >= node.pos && position < node.end) {
                        // Position was within this node.  Keep searching deeper to find the node.
                        forEachChild(node, visitNode, visitArray);

                        // don't proceed any further in the search.
                        return true;
                    }

                    // position wasn't in this node, have to keep searching.
                    return false;
                }

                function visitArray(array: NodeArray<Node>) {
                    if (position >= array.pos && position < array.end) {
                        // position was in this array.  Search through this array to see if we find a
                        // viable element.
                        for (let i = 0; i < array.length; i++) {
                            const child = array[i];
                            if (child) {
                                if (child.pos === position) {
                                    // Found the right node.  We're done.
                                    currentArray = array;
                                    currentArrayIndex = i;
                                    current = child;
                                    return true;
                                }
                                else {
                                    if (child.pos < position && position < child.end) {
                                        // Position in somewhere within this child.  Search in it and
                                        // stop searching in this array.
                                        forEachChild(child, visitNode, visitArray);
                                        return true;
                                    }
                                }
                            }
                        }
                    }

                    // position wasn't in this array, have to keep searching.
                    return false;
                }
            }
        }

        const enum InvalidPosition {
            Value = -1
        }
    }

    /** @internal */
    export function isDeclarationFileName(fileName: string): boolean {
        return fileExtensionIs(fileName, Extension.Dk);
    }

    /** @internal */
    export function isJsonFileName(fileName: string): boolean {
        return fileExtensionIs(fileName, Extension.Json);
    }
}
